perm filename TODO.LGD[CLS,LSP] blob
sn#847838 filedate 1987-10-28 generic text, type C, neo UTF8
COMMENT ⊗ VALID 00034 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00005 00002 *1. Settle on a terminology for initargs. Shall we say that
C00006 00003 ∂22-Sep-87 2008 Moon@STONY-BROOK.SCRC.Symbolics.COM Status of CLOS decisions
C00066 00004 <done>
C00093 00005 ∂12-Oct-87 1459 Gregor.pa@Xerox.COM make-mumble functions
C00098 00006 <done>
C00104 00007 <done>
C00146 00008 <done>
C00152 00009 <done>
C00160 00010 ∂14-Oct-87 0827 @STONY-BROOK.SCRC.Symbolics.COM,@JUNCO.SCRC.Symbolics.COM:skeene@STONY-BROOK.SCRC.Symbolics.COM status of "object" or "standard-object"
C00163 00011 <done>
C00168 00012 >>>> Mechanical Tasks:
C00171 00013 Functi Things
C00183 00014 <done>
C00192 00015 <done>
C00199 00016 <done>
C00211 00017 ∂15-Oct-87 2151 Bobrow.pa@Xerox.COM Re: Writing
C00213 00018 <done>
C00222 00019 ∂16-Oct-87 0833 skeene@STONY-BROOK.SCRC.Symbolics.COM don't forget the hardcopy
C00224 00020 <done>
C00227 00021 ∂24-Sep-87 0915 Bobrow.pa@Xerox.COM Redefining Classes
C00234 00022 ∂30-Sep-87 0936 Moon@STONY-BROOK.SCRC.Symbolics.COM Constructors
C00256 00023 ∂24-Sep-87 0915 Bobrow.pa@Xerox.COM Redefining Classes
C00263 00024 ∂20-Oct-87 1353 Moon@STONY-BROOK.SCRC.Symbolics.COM documentation documentation
C00268 00025 ∂20-Oct-87 1342 Moon@STONY-BROOK.SCRC.Symbolics.COM Finalize-inheritance
C00271 00026 ∂19-Oct-87 0905 Moon@STONY-BROOK.SCRC.Symbolics.COM Class-changed
C00275 00027 ∂19-Oct-87 0917 Bobrow.pa@Xerox.COM Re: Redefinition
C00278 00028 ∂19-Oct-87 0941 Bobrow.pa@Xerox.COM Re: Redefinition
C00283 00029 ∂19-Oct-87 0946 Bobrow.pa@Xerox.COM Re: Redefinition
C00285 00030 ∂23-Oct-87 1457 Gregor.pa@Xerox.COM Clear Versus Black Box
C00290 00031 As of: Oct 26, 15:52
C00291 00032 ∂26-Oct-87 1942 Moon@STONY-BROOK.SCRC.Symbolics.COM Constructors
C00293 00033 ∂26-Oct-87 2146 COMMON-LISP-OBJECT-SYSTEM-mailer Some open issues
C00315 00034 ∂28-Oct-87 0856 Common-Lisp-Object-System-mailer Re: Proof of CLOS Document
C00323 ENDMK
C⊗;
*1. Settle on a terminology for initargs. Shall we say that
``The initargs that fill a slot are the union of the initargs....''
*2. Error terminology
*3. Inheritance of class options
4. For functi.tex: slot-boundp, slot-makunbound
*5. setf- methods etc
∂22-Sep-87 2008 Moon@STONY-BROOK.SCRC.Symbolics.COM Status of CLOS decisions
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 22 Sep 87 20:07:07 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 239307; Tue 22-Sep-87 23:08:07 EDT
Date: Tue, 22 Sep 87 23:07 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Status of CLOS decisions
To: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <870922230752.1.MOON@EUPHRATES.SCRC.Symbolics.COM>
The following has been updated from my notes from last week's
meeting. I apologize for the great length and uneven level of detail.
I believe that this accurately reflects the decisions made by the CLOS
working group, so if you find any discrepancies, or anything you disagree
with, please speak up now.
This file reflects Moon's understanding of the status of various CLOS issues,
concentrating on the more minor issues. The goal is to make sure that nothing
is overlooked, and especially to make sure that issues that have been brought up
and resolved are not forgotten before they get into the document. I've removed
most comments that were purely editorial comments on the document. I also
haven't tried to keep track of all the purely meta-object issues. I've edited
things to be as brief as possible.
All page references are to the 87-002 version of the CLOS document.
The file is divided into pages as follows:
0. This page of general outline
1. Documented holes in chapters 1 and 2 of 87-002
2. Things that have been already decided (but may not be in the document yet)
3. Issues with no apparent remaining disagreement
4. Small issues needing discussion
5. Issues whose status is unclear, maybe to be tabled
6. Things to do another day
7. Big issues needing discussion, each on its own page
==================================================
DOCUMENTED HOLES IN CHAPTERS 1 AND 2 OF 87-002
We publicly promised X3J13 that we would finish these holes and also have a new
draft of 87-003 by the next meeting (November).
*1-5, 2-44 The initialization protocol for make-instance is not yet
specified.
Agreed in September, except for a few meta-object details.
*1-13, 1-26, 2-14 Which Common Lisp types will have corresponding classes
is still under discussion.
Document has been updated in draft.
Need Cleanup Committee proposals for fixes to the type system.
*2-7, 2-46 [The proposed extension to call-next-method has been accepted.]
This may not have been put into the document yet.
2-41, 2-48 [Perhaps we can adopt the condition signalling system now.]
==================================================
THINGS THAT HAVE BEEN ALREADY DECIDED (BUT MAY NOT BE IN THE DOCUMENT YET)
27 May 87 call-next-method is allowed to take arguments, however it is an error
to give it arguments that would change the set of applicable methods. I think
we're saying this signals an error, and mentioning that in some simple cases the
lack of need for an error check can be proved at compile time, but in general a
run-time check is required. Specify precisely the type of error signalling.
Agreed in September. New writeup approved.
10 June 87 The document has been updated with a discussion of how the standard
type classes are organized.
8/9/87 Gregor promised to draw a picture.
2-16 (slot-name form) is not allowed as an abbreviation
for (slot-name :initform form). People have been assuming this,
we have to document explicitly that it is not allowed.
The decision to reject (slot-name form) was made at the July meeting.
2-19 uninitialized slots should be an error to reference, not be defined
to return an unstandardized value with no error. I'm willing not to require
that it signals an error if people feel that would be an undue burden,
otherwise I prefer that reading an uninitialized slot signals an error.
In July we decided that signalling an error here should depend on the
declared safety level. Dick has proposed terminology for this.
In September, we switched to a different idea, requiring reading of an
uninitialized slot to call the slot-uninitialized generic function,
regardless of safety level. The default method signals an error.
p2-19 Values: I thought we agreed that all top level forms should return
the object. It says here defclass "returns the name of the class"
p2-22 Same comment as 2-19, for defgeneric-options
2-24 ditto for defgeneric-options-setf
In July we decided to return the object for all CLOS defxxx functions (being
inconsistent with Common Lisp, but consistent within CLOS). The document file
has been updated. DEFINE-METHOD-COMBINATION returns the name.
p2-39 Arguments: "list of t's" should be replaced by "list whose elements are
the class named t" since get-method only takes specializers, not names of
specializers.
Agreed.
2-42 make-generic-function should be deleted, redocumented as a class
that can be given to make-instance
July: Agreed
2-45 make-method should be deleted, redocumented as a class
that can be given to make-instance
July: Agreed
2-54 in the Amendments: Clarify that because class names and classes are
type-specifiers, they can be validly be used in THE special forms and in TYPE
declarations. We forgot this when we clarified that class objects can be used
with TYPEP and SUBTYPEP.
July: agreed
DEFGENERIC-OPTIONS acquired a :METHOD option, whose syntax is the syntax of
DEFMETHOD without the generic-function name, at the September meeting.
Consequently, DEFGENERIC-OPTIONS has been renamed to DEFGENERIC. It is to
be explained in terms of a call to ENSURE-GENERIC-FUNCTION followed by
zero or more invocations of DEFMETHOD.
DEFGENERIC-OPTIONS-SETF and DEFMETHOD-SETF were removed in September.
Instead, DEFMETHOD takes on the syntax of DEFMETHOD-SETF, with two
lambda-lists, when the generic-function name is a list whose car is SETF
and whose cadr is the reader-function-name. Thus we have a limited
function-spec facility where (SETF reader) is a writer-function-name.
DEFGENERIC works analogously. SYMBOL-FUNCTION, FBOUNDP, FMAKUNBOUND,
and ENSURE-GENERIC-FUNCTION will also accept these function-specs.
[This is conditional on figuring out how to fix SETF in Common Lisp]
GENERIC-FUNCTION is a new special form approved in September. Its subforms
are similar to those of DEFGENERIC, omitting the name and the SETF variant,
but it returns an anonymous generic-function object rather than defining a
named generic function.
GENERIC-LABELS and GENERIC-FLET are new special forms approved in
September. Their syntax resembles DEFGENERIC in exactly the way that the
syntax of LABELS and FLET resembles DEFUN.
[In the notes I have, the lambda-list is omitted, but that can't be
right since the :argument-precedence-order option depends on having
the lambda-list.]
WITH-ADDED-METHODS is a new special form approved in September. It is
similar to GENERIC-LABELS but also copies methods from another generic
function with the same name in an outer contour.
WITH-SLOTS was thoroughly revised in September. It now lists explicitly
the slots to be made accessible and the pseudo-variable-names by which they
will be accessible. It no longer calls accessor functions. It no longer
takes any keyword options. It no longer accesses multiple instances in
a single level of nesting. The calls to SLOT-VALUE produced by expansion
of WITH-SLOTS can still get specially optimized in some contexts such
as bodies of methods.
SYMBOL-MACROLET was added in September. It is the basic mechanism that
is used to implement WITH-SLOTS as well as user-written macros for some
of the other things that the old WITH-SLOTS did and for "virtual slots."
It allows substitution of forms for pseudo-variable-names within a
lexical scope.
The :ACCESSOR-PREFIX and :READER-PREFIX options to DEFCLASS, and the
:PREFIX option to WITH-SLOTS, were removed in September.
The function NEXT-METHODS was added in September. It is scoped the same as
CALL-NEXT-METHOD, takes no arguments, and returns a list of method objects,
of which the first is the one that CALL-NEXT-METHOD calls. The effect of
modifying the list is undefined.
[rpg: This should be NEXT-METHODP]
The function ENSURE-GENERIC-FUNCTION was added in September. It takes a
name, which is a symbol or a SETF function-spec, and named-arguments
corresponding to all the features of DEFGENERIC other than :METHOD, and
does what DEFGENERIC does.
SYMBOL-CLASS is the function that maps from a symbol to the class it
names. It can be SETF'ed. The new functions CBOUNDP and CMAKUNBOUND
were added to complement this. SETF of SYMBOL-CLASS is undefined for
certain built-in class names (to be defined).
SYMBOL-FUNCTION, FBOUNDP, FMAKUNBOUND, ENSURE-GENERIC-FUNCTION,
SYMBOL-CLASS, CBOUNDP, and CMAKUNBOUND take an optional environment
argument, which controls name-to-object mapping. These environments
are the same as the &environment argument to macro expanders, and
are typically used to distinguish between compile-time and run-time
environments. The detailed semantics of these environments will be
defined at the meta-class and implementation levels.
The TRACE-EXECUTION generic function was approved for addition at the
meta-object level in September. It is the underlying function behind
TRACE but provides some additional features.
The EXACT-TYPE declaration was approved in September. It is similar
to the TYPE declaration, but does not permit the value to be a subtype.
This is most useful when the type is a class.
Some simplifications to the short-form of DEFINE-METHOD-COMBINATION were
approved in September; the method qualifier is no longer optional and no
longer a keyword symbol.
NO-APPLICABLE-METHOD is a generic function, added in September, that
is called when a generic function is called but no applicable methods
exist. The arguments are the original generic function, the first
argument, and then all of the arguments (including the first); the
lambda-list indicates two required parameters and an &rest parameter.
SLOT-EXISTS-P was added in September; it takes an object and a slot-name
and returns a Boolean.
The following functions found in 87-002 will be removed or renamed:
Function Removed Replacement
class-named symbol-class
defgeneric-options defgeneric
defgeneric-options-setf defgeneric
defmethod-setf defmethod
get-setf-generic-function ensure-generic-function
make-generic-function make-instance
make-method make-instance
multiple-value-prog2 (none)
==================================================
ISSUES WITH NO APPARENT REMAINING DISAGREEMENT
1-12 Should defclass be allowed to change the metaclass of an existing
class? Under what conditions should a subclass of standard-class have
the same properties wrt instance updating as standard class?
Gregor says the metaclass protocol includes a predicate function that controls
whether the metaclass can be changed, which depends on whether the
representations differ and existing instances might not be transformable.
Some cross-reference to this should be added to the documentation of DEFCLASS.
1-15 to 1-22 Several errors in the formal description of class precedence and
method combination, pointed out by Jim Kempf on 4 August and 27 July, need to be
corrected. These are editorial changes only, that is, they make what the
document says conform to what I believe our intent to have been.
2-35 The argument order of the setf method ought to be documented here.
In July we suggested making the new-value argument a required argument that
comes after all the other required arguments, and before the optional, rest,
and keyword arguments. It's important that this depends only on the two
lambda-lists, and not on any context such as the generic function object.
We still have defmethod-setf so that most users don't have to think about it
(only users making setf methods "directly").
[But in September, that was changed. Instead, defmethod takes on the syntax
of defmethod-setf, with two lambda-lists, when the generic-function name
is a list whose car is SETF.]
The rule, carefully worded so as to work in the face of implementations with
non-standard lambda-list-keywords, is that the setf-lambda-list is inserted
into the normal lambda-list immediately after the last parameter-specifier
that precedes &optional, &rest, &key, or &aux. This is implemented by the
following function (should it be standardized as part of CLOS?):
(defun combine-setf-lambda-lists (lambda-list setf-lambda-list)
(do ((ll lambda-list (cdr ll))
(tail lambda-list))
((or (null ll) (member (car ll) '(&optional &rest &key &aux)))
(when (null ll)
(setq tail nil))
(append (ldiff lambda-list tail) setf-lambda-list tail))
(unless (member (car ll) lambda-list-keywords)
(setq tail (cdr ll)))))
What about the setf of values extension that Common Lisp provides syntactic
space for but does not currently prescribe? We're not going to allow that for
setf of generic functions.
September: This is still hung up on deciding what changes to Common Lisp to
recommend, so as to make setf-functions behave consistently.
2-50 Should we flush multiple-value-prog2, as leading to more discussion than is
warranted by its simplification of the presentation of define-method-combination?
Kempf: Yes.
Moon: Yes.
September: We seem to have forgotten to discuss this.
2-51 It has been suggested that print-object should take a depth argument.
Moon strongly disagrees and points to the fourth bullet. I believe this issue
was discussed to death on the Common Lisp mailing list a few months or a year ago.
The point is that every single method for print-object should not have to deal
with *print-level*; that's unmodular.
Kempf raised a consistency argument (with defstruct?) but we decided
not to change print-object.
2-54 slot-missing should be documented in chapter 2
Gregor:
slot-missing is a generic function which takes three required
arguments and an optional fourth argument. The three required
arguments are the class of the object, the object and the name of the
slot. The fourth argument is the new value for the slot if
slot-missing is being called by setf of slot-value. This set of
arguments allows people to define methods on the metaclass for
handling slot-missing. For example, a low performance implementation
of dynamic slots could work this way.
(defmethod slot-missing ((class dynamic-class) obj slot
&optional (nv nvp))
(if nvp
(set-dynamic-slot obj slot nv)
(get-dynamic-slot obj slot)))
The default method on slot-missing signals an error of the same name.
September: We changed this slightly. It takes a required fourth argument,
which is a symbol describing the operation being performed on the slot,
one of slot-value, setf, slot-boundp, or slot-makunbound. The optional
new-value argument is now the fifth argument.
Symbol-function (the user callable primitive) needs to be split from the
subprimitive for implementors that gets and sets the "real" function definition
of a symbol. This is so when a symbol's function definition is a generic
function object, the "real" definition can be something that is easier for the
implementation to call.
July: We need to say explicitly somewhere that calling symbol-function
of the name of a generic function is required to return the generic
function object, not the "real" definition.
Kempf: I don't see splitting SYMBOL-FUNCTION as an issue for the standard,
though it may be for certain implementations.
Moon: Right, the only standardization issue is making sure
SYMBOL-FUNCTION returns the generic function object, not something internal.
Not all of the "corrections and amendments" handed out at the March 1987
X3J13 meeting in Palo Alto have been put into the document yet. The
corrections are in but the amendments and the revised explanation of slot
inheritance are awaiting review by the group. The revised slot inheritance
writeup is later in this file.
==================================================
SMALL ISSUES NEEDING DISCUSSION
1-17 "It is currently under discussion whether to provide constructs
for giving generic functions local names." Do we want to have this
discussion, or to punt on this syntax. I recall we did come up with some
reasonable semantics for a GFLET and GFLABELS.
RPG has written a proposal.
September: This proposal was modified and then adopted.
1-19 "... Common Lisp be modified to include the following semantics
for quote in a type specifier:
(deftype quote (object) '(member ,object)))"
Has any proposal for this been given to the cleanup committee?
Yes: ISSUE: TYPE-MEMBER-SINGLETON, Proposal TYPE-MEMBER-SINGLETON:QUOTE
It hasn't really gone through the mill yet, though.
In July Moon volunteered to make sure this happens, but in August
Moon said he didn't like it and we should use MEMBER in parameter
specializers instead (there is a proposal for that pending now).
Moon: I favor flushing the QUOTE type specifier.
September: We renamed it from QUOTE to EQL and Gregor will make a
proposal to the cleanup committee.
1-24 Should we have a call-next-method? which calls such a next method
if it exists, else returns nil (rather than signalling an error?). This
seems useful rather than having to define many base methods on object.
Common Lisp reserves question mark for the user; this could be named
CALL-NEXT-METHOD-OR-NIL, or something like that.
Kempf: signalling an error is sufficient, this probably isn't needed.
In July we wondered whether there should be a way to get a list of
the remaining methods. What operations on that list should be
permitted?
- checking whether it's nil gives the desired feature
- checking its length
- doing something with list elements (presumably method objects)
- modifying the list is clearly out
- does the list have dynamic or indefinite extent?
This may be expensive enough that it can't substitute for
CALL-NEXT-METHOD-OR-NIL.
I think we're awaiting proposals on these two issues, as well as a
concensus on whether we need these features.
September: We adopted a NEXT-METHODS function, scoped the same as
CALL-NEXT-METHOD, and decided that there was no need for a function
such as CALL-NEXT-METHOD-OR-NIL that combines the two.
2-30: Note the third paragraph on p.2-30 of 87-002, speaking of signalling an
error when the arbitrary order of two methods affects the result. I suggest
that this error be mandatory instead of optional.
September: Agreed.
2-38 need a way to recover documentation of a method-combination type
July: do this by adding a new value for the second argument to DOCUMENTATION.
But the whole writeup on DOCUMENTATION is screwy, and we need a new proposal.
When the CL-Cleanup subcommittee finishes cleaning up the concept of
"definition" (I think it's waiting for Masinter to propose something)
then DOCUMENTATION should follow.
2-57 What does with-slots do for slots that exist in the class but don't
have accessors, when :use-accessors t is specified (or defaulted)?
July: it shadows any outer bindings of the slot name, and if you
actually access that pseudo-variable, it signals an error.
Gregor: What if by the time you actually run the body of the method, the slot
has an accessor? It all hinges on exactly when macro-expansion time is and
that is not specified.
There are two issues here:
(1) Exactly when is the set of names scoped with with-slots determined?
(2) Exactly when is the presence or absence of an accessor for a name
determined?
We need a proposal.
September: WITH-SLOTS was completely changed; the set of slots is now
listed explicitly, accessors are never called, and both issues go away.
What can be done with method objects, e.g. can one method be added
to more than one generic function?
Gregor: I believe it should signal an error to attempt to put a method on more
than one generic function. My model of this is that if you want to do
something like that, you can take one function, use it as the method function
of multiple methods, each of which would be on a different generic function.
September: Agreed.
I'm not sure if we said anywhere what happens when you call a generic
function and there is no applicable method; I think it ought to signal
an error.
Gregor:
This is a generic function like slot-missing. There is a generic
function NO-APPLICABLE-METHOD which is called with the generic function
as the first argument and the arguments to the generic function as
the remaining arguments. This allows people to define a method to
handle the no matching method case either on the class of the generic
function or on the individual generic function. The default method
for no-applicable-method signals an error of the same type.
The error message should give some information about
the classes of the parameters, to help debugging.
CALL-NEXT-METHOD with no more methods should do something similar,
but not identical. Well, we left it simply signalling an error.
September: Agreed.
funcallable-standard-class should be documented. It is a metaclass.
This is what makes generic function objects funcallable. There is a slot
that is the actual function that gets called.
I think Gregor volunteered to propose details.
September: deferred.
We need to decide whether class-name of an anonymous class is nil or
signals an error.
The concensus seems to be to return nil.
September: Agreed.
What does type-of return when applied to an instance of an anonymous
class?
September: Agreed that type-of a meta-instance of standard-class returns
(if (eq (symbol-class (class-name (class-of object))) (class-of object))
(class-name (class-of object))
(class-of object))
(This definition might be only approximate when error and timing
considerations are added.)
==================================================
ISSUES WHOSE STATUS IS UNCLEAR, MAYBE TO BE TABLED
2-26 I (Bobrow) believe that short form method combination ought to be a
macro in the standard library, and documented there, not in the basic
principles. I think the standard combinations :append, :and, :or, ...
should also be put in the standard library too.
Kempf agrees. Moon can't have an opinion until he knows what this
library is and whether it's going to be as much of a joke as the
Common Lisp Yellow Pages.
Moon: I oppose this.
September: Dropped.
2-46 Last line: If call-next method is extended ..." I see no reason
for additional keyword arguments.
Moon doesn't remember the issue. It may have been consistency; if call-next-method
can specify the arguments, then so can make-method-call. You need one keyword
argument to specify the methods and another to specify funcall versus apply.
It could also have been that call-next-method would be implemented in terms of
make-method-call, and therefore would need to be able to specify the arguments.
September: Dropped.
2-6 call-next-method dynamic versus indefinite extent
The document says it has dynamic extent; we need to be sure that we
really mean that. In July we said "implementation flexibility, not
really a language thing", but I'm damned if I can figure out what
that means (optimizing calculation of the effective method?).
Gregor: I am pretty sure what we meant was we didn't want to have to worry
about the case where someone returns a closure that includes a call
to call-next-method, and then redefines the class or method structure
so that the closure would have to call different 'next methods'.
Moon: Oh, so this is different from extent, because they could do that
redefinition before the method returns. So either we should say it
captures the set of next methods at a particular instant, or it's
undefined what happens if you redefine.
September: discussion continues in the mail.
2-9 semantic difficulties discussion was shortened for the document so much
that much of the point was lost. At some point we need to decide how much
we want to standardize about this and where we want to say it; in the main
standard or in some kind of implementation guide.
[no response to this so far, Moon should propose I guess]
September: Postponed.
2-16 boa-arglist should support &key and &allow-other-keys.
2-18 default boa-arglist to be specified
Status depends on whether object-creation proposal includes constructors.
September: Postponed. Moon is to send a proposal for how to add
constructors to the agreed upon object creation protocol, or else
we will flush them.
Which symbols defined by the standard go in what package?
July: I think we said some will go in LISP: and some will go in CLOS: and
we don't know yet where to draw the line.
The top level macros and functions should be part of LISP.
The internal functions specified for the sake of metaclass programming
can reside in CLOS.
If CLOS is an optional part of CL, are the symbols in the LISP package
even when the option is not present? Probably.
September: Postponed.
Kempf 29 Jul 87: There was no mention made of compile time optimization,
which I believe I made some initial proposals on in late April or early May.
I've been meaning to revisit them.
September: Postponed.
==================================================
THINGS TO DO ANOTHER DAY
This is a list of issues that were specifically deferred at the September
meeting, and haven't been taken care of yet.
Specify the condition names used by CLOS and their subtype relationships.
Throughout the CLOS spec, specify which condition is signalled where we
now say that an error is signalled.
In general, clean up the terminology, make sure that it is consistent,
and make sure that the document includes a complete and accurate glossary.
Consider renaming "local slot" to "instance slot" and "shared slot" to
"class slot."
Consider defining the term "proper name" to refer to the test involving
class-name and symbol-class that type-of is now defined to do.
Vote on dynamic or indefinite extent of call-next-method, after issues
are explicated in the mail.
Add examples to each operator description in chapter 2.
Reconsider [how?] use of setf and with-added-methods.
Determine inheritance of environments in name-to-object mapping.
Some people want a table in the description of lambda-list congruence.
Some people want a discussion of how to think about the class precedence
list algorithm, showing its effect on some typical class definitions, and
giving some general rules of thumbs that will help people understand the
effect of the CPL algorithm. (This would be things like two trees of
superclasses will remain non-commingled if they are non-intersecting or
intersect only at the top).
Decide about the proposal for a :precedence defclass option.
Look at the amendments distributed in March, determine where new
writing (rather than a simple edit) is required, then determine
who will do the writing.
==================================================
REVISED ``INHERITANCE OF SLOTS AND SLOT OPTIONS'' SECTION:
[For readability all TEX formatting has been temporarily removed]
The set of the names of all slots accessible in an instance of a class,
C, is the union of the sets of names of slots defined by C and its
superclasses. At most one slot of a given name can be accessible in an
instance.
In the simplest case, only one class among C and its superclasses
defines a slot with a given slot name. If the class that defines the
slot is not C, we say that the slot is inherited. The characteristics
of the slot are determined by the slot specifier of the defining class.
If the :allocation slot option is omitted, :instance, or :dynamic, then
it specifies a local slot and each instance of C has its own slot that
stores its own value. If the :allocation slot option is :class, then it
specifies a shared slot, the class that defined the slot stores the
value, and all instances of C access that single slot.
In general, more than one class among C and its superclasses can define
a slot with a given name. In such cases, only one slot with the given
name is accessible in an instance of C, and the characteristics of that
slot are a combination of the several slot specifiers, computed as
follows.
- All the slot specifiers for a given slot name are ordered
from most specific to least specific, according to the order in
the class precedence list of C of the classes that define them.
- The allocation of a slot is controlled by the most specific slot
specifier. If the most specific slot specifier does not contain
an :allocation slot option, :instance is used. Less specific slot
specifiers never affect the allocation.
- The initform of a slot is controlled by the most specific slot
specifier that contains an :initform slot option. If no slot specifier
contains an :initform, the slot has no default initial value form.
- The type of a slot is (and T1 T2 T3...), where T1, T2, T3, and so on
are the :type slot options contained in all of the slot specifiers. If
no slot specifier contains :type, the type is t.
The :reader and :accessor slot options were not mentioned because
they create methods, rather than defining characteristics of a slot.
Reader and accessor methods are inherited in the sense described in the
section ``Inheritance of Methods.''
A consequence of the allocation rule is that shared slots can be
shadowed. If a class C-sub-1 defines a shared slot named S, normally
that single slot is accessible in instances of C-sub-1 and all of its
subclasses. However, if C-sub-2 is a subclass of C-sub-1 and also
defines a slot named S, C-sub-1's slot is not shared by instances of
C-sub-2 and its subclasses. See S2 in the section ``Examples of
Inheritance.''
A consequence of the type rule is that the value of a slot satisfies the
type constraint of each slot specifier that contributes to that slot.
Note that an implementation may or may not choose to check the type of
the new value when initializing or assigning to a slot.
Methods that access slots know only the name of the slot and the type of
the slot's value. Suppose a superclass provides a method that expects
to access a shared slot of a given name and a subclass defines a local
slot with the same name. If the method provided by the superclass is
used on an instance of the subclass, the method accesses the local slot.
==================================================
LAMBDA-LIST CONGRUENCE
Changes to Lambda-list Congruence Rules (p.1-20): Rules 1, 2, and 6 remain the
same, except for wording problems, while rules 3-5 need to be replaced to
implement the new rules for &KEY and to fix the interaction among &KEY, &REST,
and &ALLOW-OTHER-KEYS. The new rules for congruence are the following:
These rules define the congruence of a set of lambda-lists, including the
lambda-list of each method for a given generic function and the lambda-list
specified with DEFGENERIC, if present. For (SETF generic) methods, these
rules apply to the effective lambda-list produced by combining the two
specified lambda-lists according to the rules on page nnn.
1. Each lambda-list must have the same number of required parameters.
2. Each lambda-list must have the same number of optional parameters.
Each method can supply a different default for an optional parameter.
3. If any lambda-list uses &REST or &KEY, each lambda-list must use one or
more of these.
4. If the DEFGENERIC uses &KEY, each method must accept all of the named
arguments mentioned after &KEY in DEFGENERIC, either by accepting them
explicitly, by specifying &ALLOW-OTHER-KEYS, or by specifying &REST but not
&KEY. Each method can accept additional named arguments of its own.
The checking of the validity of named argument names is not done in each
method; instead it is done in the generic function.
5. The use of &ALLOW-OTHER-KEYS need not be consistent across lambda-lists.
If &ALLOW-OTHER-KEYS is used in any lambda-list, then any named arguments
may be used in the call to the generic function.
6. The use of &AUX need not be consistent across methods.
September: Agreed.
==================================================
NAMED ARGUMENTS
Change the meaning of &KEY in the lambda-list of DEFMETHOD and DEFGENERIC:
When a generic function, or its methods, use &KEY in the lambda-list, the
specific set of named arguments accepted by the generic function varies
depending on the applicable methods. The named arguments accepted by the
generic function for a particular call are the union of the named arguments
accepted by any applicable method and the named arguments mentioned after
&KEY in DEFGENERIC, if any. There is no attempt to exclude methods that
are applicable but are not actually called. Note that in standard method
combination, all applicable methods are potentially callable, if
CALL-NEXT-METHOD is used. A method that has &REST, but not &KEY, does not
affect the set of acceptable named arguments. If the lambda-list of any
applicable method or of the DEFGENERIC has &ALLOW-OTHER-KEYS, all named
arguments are accepted by the generic function.
Lambda-list congruence rules require that each method accept all of the named
arguments mentioned after &KEY in DEFGENERIC, either by accepting them
explicitly, by specifying &ALLOW-OTHER-KEYS, or by specifying &REST but not
&KEY. Each method can accept additional named arguments of its own,
in addition to the "standard" named arguments mentioned by DEFGENERIC.
The implementation of &KEY is in three parts:
(1) The function METHOD-NAMED-PARAMETERS retrieves a list of the
named-parameter names (typically, but not necessarily, keyword symbols)
explicitly accepted by a method. If the method's lambda-list contains
&ALLOW-OTHER-KEYS, METHOD-NAMED-PARAMETERS returns that symbol rather than
an infinite list. If the method's lambda-list does not contain &KEY,
METHOD-NAMED-PARAMETERS returns NIL. Note that this means that if the
method's lambda-list contains &REST but not &KEY, it is not considered to
accept any named-arguments explicitly. The implementation of
METHOD-NAMED-PARAMETERS may be in terms of the existing METHOD-LAMBDA-LIST
function.
(2) The macro expansion of DEFMETHOD and related method-defining macros,
when the method uses &KEY, puts &ALLOW-OTHER-KEYS into the lambda-list of
the function. This does not affect the result returned by
METHOD-NAMED-PARAMETERS nor METHOD-LAMBDA-LIST; it simply disables validity
checking of named-argument names when the generic-function-to-method
dispatching mechanism calls the method. Design rationale: it's done with
&ALLOW-OTHER-KEYS, rather than :ALLOW-OTHER-KEYS T, so that methods with
&REST parameters will not see anything extra in their rest parameter.
(3) The generic-function-to-method dispatching mechanism checks the
validity of the argument list when the generic function or any applicable
method uses &KEY and none of them uses &ALLOW-OTHER-KEYS; it cannot rely on
the normal function-call mechanism to check the validity of the argument
list. This is accomplished by collecting the acceptable named-argument
names from the applicable methods and from DEFGENERIC, and checking the
arguments against the union of those lists. If for any applicable method
METHOD-NAMED-PARAMETERS returns &ALLOW-OTHER-KEYS, the whole check is
skipped. CLtL p.62 says named-argument name mismatch "is an error", so the
argument list validity checking in the generic-function-to-method
dispatching mechanism should conform to that and signal an error under
implementation-dependent control.
For example:
(defmethod width ((c character) &key font) ...)
(defmethod width ((p picture) &key pixel-size) ...)
;assume there are no other methods for width and no defgeneric
(width x :font 'foo :pixel-size 10) is an error unless x is
both a character and a picture. The acceptable arguments are
determined by the applicable methods, not all methods.
September: Agreed with changes that have been edited-in above.
==================================================
CLASS REDEFINITION
Clarify redefining classes, find a better name for updating-obsolete-instance.
There was much discussion, which I'm not going to try to summarize here,
and we agreed to adopt a simpler solution than what we had before and to
keep discussing it over the net. Class redefinition, CHANGE-CLASS, and
COERCE will be three independent mechanisms.
<done>
∂28-Sep-87 1114 Moon@STONY-BROOK.SCRC.Symbolics.COM Revised draft of object creation proposal
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 28 Sep 87 11:13:33 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 243088; Mon 28-Sep-87 14:14:24 EDT
Date: Mon, 28 Sep 87 14:14 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Revised draft of object creation proposal
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Message-ID: <870928141430.0.MOON@EUPHRATES.SCRC.Symbolics.COM>
This version differs from the previous one I mailed out only in some
small corrections based on comments received in the mail. The terminology
has been changed back from "named argument" to "keyword argument."
It may be about time to start converting this to the text that will go
into the specification document. Any more comments first?
Draft of, and notes toward, a new object creation proposal based on
CLOS subcommittee discussions July 2, 1987. Updated based on Sep 17-18
1987 working group meeting. Updated based on mail received up to Sep 28,
and converted back to CLtL terminology for keyword arguments.
-foo- means the word foo in italics. FOO means the word foo in boldface.
PREREQUISITES
This proposal assumes keyword arguments to methods work as described in the
accompanying lambda-list congruence proposal.
The proposal assumes CL-Cleanup issue KEYWORD-ARGUMENT-NAME-PACKAGE, which
stated that the names of &key arguments do not have to be keyword symbols.
The terminology of CLtL is used for discussing keyword arguments, but it
should be understood that keyword names are not necessarily symbols in
the keyword package; that's just a default convention.
CONCEPTS TO BE ADDED TO 87-002
-initarg-. An initarg (initialization argument) is a keyword argument that
can be used to control object creation and initialization. The &key arguments
to MAKE-INSTANCE are initargs. It is often convenient to use keyword symbols
to name initargs, but the name of an initarg can be any symbol, including NIL.
-initarg list-. An initarg list (initialization argument list) is a list of
alternating initarg names and values. Its structure is identical to a
property list and also identical to the portion of an argument list processed
for &key parameters. As in those lists, if an initarg name appears more than
once in an initarg list, the leftmost occurrence supplies the value and the
remaining occurrences are ignored. The arguments to MAKE-INSTANCE, after the
first, are an initarg list. As in an &key argument list, :ALLOW-OTHER-KEYS
can appear in an initarg list, and if its value is non-NIL, error-checking of
initarg names is disabled.
-slot-filling initarg-. An initarg associated with a slot. If the initarg
has a value in the initarg list, the value is stored into the slot of the
newly-created object, overriding any initform associated with the slot. A
single initarg can fill more than one slot. A slot-filling initarg that
fills a shared slot stores its value into the shared slot, replacing any
previous value.
-method-implemented initarg-. An initarg associated with a method. When
an object is created, the method is called with the initarg's value as an
argument and the method uses the value in any way it likes. If the initarg
has no value in the initarg list, the method's lambda-list supplies a
default value. A single initarg can be implemented by more than one
method. An initarg can be both slot-filling and method-implemented.
CHANGES TO 87-002 FEATURES
DEFCLASS gets a new :INITARG slot option, which is followed by a symbol.
The symbol becomes the name of a slot-filling initarg for this class.
This slot option can appear any number of times.
DEFCLASS gets a new :DEFAULT-INITARGS option, which is followed by a list of
alternating initarg names and default-initarg forms. If one of these initargs
does not appear in the initarg list supplied to MAKE-INSTANCE, the
corresponding default-initarg form is evaluated, then the initarg name and the
form's value are added to the end of the initarg list. The form is evaluated
every time it is used. The lexical environment in which this form is
evaluated is the lexical environment in which DEFCLASS was evaluated. The
dynamic environment is the dynamic environment in which MAKE-INSTANCE was
called. The appearance of a symbol as an initarg name in a :DEFAULT-INITARGS
option does not make that symbol a valid initarg name for the class.
The :DEFAULT-INITARGS option may be specified more than once.
[Should the name of this option be :DEFAULT-INITARGS or :DEFAULT-INITARG ?]
Method-implemented initargs are defined simply by defining a method for
INITIALIZE-INSTANCE or ALLOCATE-INSTANCE. The keyword name of each keyword
parameter specifier in the method's lambda-list becomes a method-implemented
initarg for all classes for which this method is applicable.
Initarg inheritance: The effective set of slot-filling initargs for a class C
is the union of the slot-filling initargs defined by C and its superclasses.
The effective set of method-implemented initargs for a class C is determined
by method inheritance.
Default-initargs inheritance: The set of initargs of C that have default value
forms is determined by the union of the :DEFAULT-INITARGS options of C and its
superclasses. When more than one class in the CPL specifies a default value
form for a given initarg, only the form specified by the most specific such
class in the CPL is used.
Rules when initargs are duplicated in various ways:
The :INITARG slot-option may be specified more than once for a given slot.
A single initarg can initialize more than one slot if the same initarg name
appears in more than one :INITARG slot-option.
It is valid for a given initarg name to be defined more than once as a
slot-filling initarg, as a method-implemented initarg, or both.
If two initargs that initialize the same slot, with the same or different
names, are given in the arguments to MAKE-INSTANCE, the leftmost of these
initargs in the initarg list prevails.
If two different initargs that initialize the same slot have default values,
and neither is given explicitly in the arguments to MAKE-INSTANCE,
the initarg that appears in a :DEFAULT-INITARGS slot-option in the most
specific class prevails, or if they appeared in the same class, the one whose
mention in :DEFAULT-INITARGS is leftmost in the DEFCLASS form prevails.
Defaulted initargs are appended to the end of the initarg list in this order.
If there are two different initargs that initialize the same slot, and one
was given explicitly in the arguments to MAKE-INSTANCE while the other was
defaulted via :DEFAULT-INITARGS, the explicit one prevails. (This rule is
implied by the two preceding rules, but it seems worth drawing attention to.)
If a slot has both an :INITFORM and an :INITARG slot-option, and the
slot-filling initarg is defaulted via :DEFAULT-INITARGS, the initform is not
used and is not evaluated.
An illustrative example of the above rules:
(defclass a () ((x :initarg a)))
(defclass b (a) ((x :initarg b))
(:default-initargs a 1 b 2))
FORM INITARG LIST CONTENTS OF X SLOT
(make-instance 'b) (a 1 b 2) 1
(make-instance 'b 'a 3) (a 3 b 2) 3
(make-instance 'b 'b 4) (b 4 a 1) 4
(make-instance 'b 'a 1 'a 2) (a 1 a 2 b 2) 1
Note: nothing is guaranteed about the order of evaluation of default-initarg
forms and initforms. If there are dependencies among these forms, you should
be using INITIALIZE-INSTANCE methods instead. In most programs, the initforms
and default-initarg forms are either constants or simple forms that construct
new objects; forms with side-effects are permitted, but are not typically used.
NEW FUNCTIONS TO BE ADDED
In this section, I have only sketched each function, for the sake of brevity.
Full writeups can be constructed once the overall framework has been agreed
upon. Functions are in alphabetical order, in three sections at three protocol
levels. The breakdown between the second and third levels may be changed. By
coincidence, all functions listed except SLOT-BOUNDP and SLOT-MAKUNBOUND are
generic and expected to specialize on their first argument.
>>> Tools used for simple object-oriented programming:
(INITIALIZE-INSTANCE instance &key &allow-other-keys)
MAKE-INSTANCE calls this with the freshly-created instance, any initargs that
were supplied to MAKE-INSTANCE, and any defaulted initargs. Users define
methods for this to create method-implemented initargs. Typically,
user-defined methods are :AFTER methods, however that is not a requirement.
The primary method for INITIALIZE-INSTANCE is system-supplied and takes care
of the slot-filling initargs. For each slot (whether local or shared):
- if an initarg was specified or defaulted that fills that slot, its
value is stored into the slot. (This is true even if a :BEFORE method
has modified the slot.)
- otherwise, if the slot is uninitialized and it has an initform, the
initform is evaluated and the result is stored into the slot.
- the duplicate-resolution rules mentioned earlier are obeyed.
An implementation is permitted to optimize initforms that neither produce nor
depend on side-effects, by evaluating them and storing them into slots before
running any INITIALIZE-INSTANCE methods, rather than handling them in the
primary INITIALIZE-INSTANCE method. This might be implemented by having the
ALLOCATE-INSTANCE method copy a prototype instance. This means that :BEFORE
and :AROUND methods for INITIALIZE-INSTANCE cannot rely on all the slots being
uninitialized at the beginning.
An implementation is permitted to optimize default value forms for slot-filling
initargs by not actually consing the complete initarg list, when the only
method that would see the complete list is the system-supplied primary method,
e.g. when no other methods use &REST. In this case default value forms can be
treated like initforms. This has no visible effects other than a performance
improvement.
(MAKE-INSTANCE class &key -initargs-...) => instance
Users call this function to create objects. Class can be either a class or
the name of a class. Meta-users can define new methods for MAKE-INSTANCE
to replace the object-creation protocol.
(SLOT-BOUNDP instance slot-name) => boolean
Allows writing INITIALIZE-INSTANCE :AFTER methods that only initialize slots if
they haven't been initialized already.
(SLOT-MAKUNBOUND instance slot-name) => instance
Restores a slot to the uninitialized condition.
>>> Functions underlying the tools
It is undefined what happens if you modify the values returned by any
of the functions in this section. It is permitted, but not required,
for an implementation to return values that share with internal data
structures. Some of these functions will be SETF'able; which ones
remain to be determined.
(CLASS-ALL-INITARGS class) => list of initarg names, including inherited
ones. This is (REDUCE #'UNION (MAPCAR #'CLASS-DIRECT-INITARGS cpl)).
(CLASS-DIRECT-INITARGS class) => list of initarg names. This works by
computing the applicable methods for ALLOCATE-INSTANCE and for
INITIALIZE-INSTANCE and examining their lambda-lists (using
METHOD-KEYWORD-NAMES), then combining that with the class's list of
slot-filling initargs.
(CLASS-ALL-INITARG-DEFAULTS class)
=> ((initarg-name default-value-function default-value-form)...)
(CLASS-DIRECT-INITARG-DEFAULTS class)
=> ((initarg-name default-value-function default-value-form)...)
This reflects the :DEFAULT-INITARGS option. Default-value-form is the form
that was originally specified, and is retained purely for explanatory
purposes. default-value-function is what gets actually called; its effect is
equivalent to enclosing default-value-form in the appropriate lexical
environment. Default-value-function takes no arguments.
(CLASS-ALL-SLOT-INITARGS class) => ((initarg-name slot-name...)...)
(CLASS-DIRECT-SLOT-INITARGS class) => ((initarg-name slot-name...)...)
This reflects the :INITARG slot-option.
(COMPUTE-APPLICABLE-METHODS generic argument-list) => list of methods
(METHOD-KEYWORD-NAMES method) => list of symbols or &ALLOW-OTHER-KEYS,
indicating the keyword names of the keyword parameter specifiers in
the method's lambda-list. The result is the symbol &ALLOW-OTHER-KEYS
instead of a list if the method's lambda-list contains that symbol.
>>> Meta-object functions
(ALLOCATE-INSTANCE class &key &allow-other-keys) => instance
Meta-users can replace the system-supplied, implementation-dependent method
for this. Any keyword arguments accepted by applicable ALLOCATE-INSTANCE
methods become valid initargs.
(CHECK-INITARGS class initarg-list)
Meta-users could replace the system-supplied method that implements the
normal rules for initarg validity.
(DEFAULT-INITARGS class initarg-list) => initarg-list
The system-supplied method implements the :DEFAULT-INITARGS class option
by appending initargs that do not appear in initarg-list to the end
of the returned list. The initarg-list supplied as an argument is not
modified. The order of initargs appended to the list is determined by
the duplicate-initarg rules listed earlier.
(FINALIZE-INHERITANCE class &key slots methods initargs)
This is called by the system at least once before a class is instantiated, and
is called again whenever anything relevant changes. System-supplied methods
for this conspire with methods for CHECK-INITARGS, etc., to make MAKE-INSTANCE
faster. Users with their own optimization needs can add methods for this
generic function that will precompute things based on inherited information,
and update the precomputed information whenever anything changes.
The :slots, :methods, and :initargs arguments are booleans that are true
when the specified type of inheritance needs to be recomputed.
PROCEDURAL DEFINITION OF MAKE-INSTANCE
MAKE-INSTANCE behaves as if it was defined as follows, except that certain
optimizations are permitted, as detailed below and in the description of
INITIALIZE-INSTANCE.
(defmethod make-instance ((class standard-class) &rest initargs)
(setq initargs (default-initargs class initargs))
(check-initargs class initargs)
(let ((instance (apply #'allocate-instance class initargs)))
(apply #'initialize-instance instance initargs)
instance))
(defmethod make-instance ((class-name symbol) &rest initargs)
(apply #'make-instance (symbol-class class-name) initargs))
Optimization is possible, including inlining and constant-folding of method
lookup and method bodies, provided that the programming environment either
prohibits redefining these methods or updates everything when they are
redefined. A possible example implementation would be that MAKE-INSTANCE has
a separate method for every class, which is automatically written and compiled
by the system.
This optimization relies on the FINALIZE-INHERITANCE generic function and some
unpublished slots of STANDARD-CLASS.
Because of optimization, methods for the generic functions listed may not
actually be called on every call to MAKE-INSTANCE, or may not receive
exactly the arguments that would be expected. For example, CHECK-INITARGS
may actually be called before DEFAULT-INITARGS rather than after, if it has
already been determined that the default initargs will pass CHECK-INITARGS.
Additional explicit details of permissible optimization will need to be set
forth.
MEETING OF STATED DESIGN GOALS
Lexical proximity of concepts--the declaration of an initarg as valid,
the specification of what it does, and the default if it is not supplied
are all together, in a slot specifier or in a method lambda-list.
Simple ways to do simple things--slot-filling initargs don't require the
user to write any code. Method-implemented initargs work just like
ordinary function arguments as far as the user is concerned.
Minimal number of new languages--the only addition to Common Lisp is
a mildly complicated rule for how &KEY lambda-lists of methods do
validity checking.
Ability to do everything at some level--the underlying procedural level
is available. Functions to access all the direct and inherited
information are documented.
Underlying mechanism is exposed so user can use it for other things, rather
than abusing instance creation as the only way to access the mechanism--the
combination of &KEY, METHOD-KEYWORD-NAMES, COMPUTE-APPLICABLE-METHODS, and
FINALIZE-INHERITANCE provides everything the user needs.
∂12-Oct-87 1459 Gregor.pa@Xerox.COM make-mumble functions
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 12 Oct 87 14:59:32 PDT
Received: from Semillon.ms by ArpaGateway.ms ; 12 OCT 87 14:56:37 PDT
Date: Mon, 12 Oct 87 14:56 PDT
From: Gregor.pa@Xerox.COM
Subject: make-mumble functions
To: RPG@Sail.Stanford.edu
Message-ID: <871012145631.3.GREGOR@SPIFF.isl.parc.xerox.com>
Line-fold: no
make-generic-function and make-method need to be replaced with
documentation explaining the initargs which can be passed to
make-instance when the first argument is standard-generic-function or
standard-method.
Mostly, this involves inventing some format for describing the behavior
of make-instance when its first argument is a particular class. I guess
we want to index this under the name of the class so that later when we
have more to say about the class we can put it there too. But I have no
really string opinion about this, I will defer to your opinion about
what will fit best in the documentation.
For make-generic-function, the documentation is basically correct except
that the keywords are really initargs. As I said, I don't know how you
will want to format this, but something which has the same 'meaning' as:
make-instance 'standard-generic-function &initarg ...
would be correct. The description of the arguments is correct except
that:
in the second paragraph, defgeneric-options should be defgeneric
the :generic-function-class argument should be deleted
For make-method, there should be 3 initargs :qualifiers, :specializers,
and :function. The description of the arguments is correct as it stands
but method-qualifiers needs to be replaced by qualifiers.
We didn't use to have a generic function called make-class, but clearly
it must be possible to make a class with make-instance. The problem
here is that one of the initargs will be a list of slot-description
objects which we have not yet specified. Probably we should go ahead
and spec out these arguments to make-instance anyways and say that
slot-description objects are described in chapter 3.
so it looks like this:
The purpose is to construct a standard-class. The class will be
anonymous unless it is assigned to a name with setf of class-named.
the initargs are:
:direct-superclasses
a list of class objects. This specifies that these will be the
superclasses of the class.
:direct-slots
a list of slot-description objects (see chapter 3). This specifies
that these slot-descriptions will be included in the class.
-------
<done>
∂12-Oct-87 1641 Gregor.pa@Xerox.COM with-slots and symbol-macrolet
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 12 Oct 87 16:41:01 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 12 OCT 87 16:41:30 PDT
Date: 12 Oct 87 16:39 PDT
From: Gregor.pa@Xerox.COM
Subject: with-slots and symbol-macrolet
To: RPG@Sail.Stanford.edu
Message-ID: <871012-164130-4158@Xerox>
Here are descriptions of with-slots and symbol-macrolet
WITH-SLOTS <instance-form> (<slot-entry*) &body body [macro]
slot-entry = slot-name | (variable-name slot-name)
Within the body of a with-slots form, use of slot-name macroexpands into
a call to slot-value to fetch the slot from the object. with-slots
first evaluates the instance-form once and then evaluates its body.
For example:
(with-slots position-1
(x y)
(sqrt (+ (* x x)
(* y y))))
To be able to use a different symbol as the virtual variable than the
name of the slot which will be accessed, use the extended form of the
slot entries:
(with-slots position-1
((x1 x)
(y1 y))
(with-slots position-2
((x2 x)
(y2 y))
(psetf x1 x2
y1 y2))))
Note that when with-slots expands its body, and it finds a use of setq
to set the value of one of the 'bound' variable names, it converts that
to a use of setf when it changes the use of the variable name to a call
to slot value. This means that it is legal to use setq to set the
values of the 'bound' variables. Here is an example of a with-slots
expansion which demonstrates this:
(with-slots position
(x y)
(setq x (1+ x)
y (1+ y)))
==>
(let ((#:g1 position))
(setf (slot-value #:g1 'x) (1+ (slot-value #:g1 'x)))
(setf (slot-value #:g1 'y) (1+ (slot-value #:g1 'y))))
As before, is is legal to return lexical closures over the 'variables'
bound by with-slots. But, as demonstrated in the examples, with-slots
behaves as though the <instance-form> is evaluated only once when
with-slots is entered. In particular, note the following example.
(setq closure
(let ((pos (make-instance 'position 'x 1 'y 1)))
(prog1 (with-slots pos (x y) #'(lambda () (list x y)))
(setq pos (make-instance 'position 'x 2 'y 2)))))
Now, (funcall closure) returns (1 1) not (2 2).
SYMBOL-MACROLET (<symbol-macro-binding>*) &body body [macro]
symbol-macro-binding = (symbol expansion)
Example:
For example, the first call to with-slots above might be implemented by
having it expand into:
(let ((#:g1 position-1))
(symbol-macrolet ((x (slot-value #:g1 'x))
(y (slot-value #:g1 'y)))
...))
The note about about setq's being converted to setfs also applies to
symbol-macrolet.
This mechanism makes it possible to implement versions of with-slots
which convert variable uses into calls to generic-functions, which
provide virtual slots or any of the other behavior we have wanted to
get.
Note that the addition of symbol-macrolet to the language will have an
impact (a small impact) on any cleanup committee proposal to make Common
Lisp macroexpansion environment environments first class objects.
The sysmbol-macro definitions are added to the macro expansion
environment within the symbol-macrolet form. Also macroexpand of a
symbol which has a symbol macro definition in the environment expands
the symbol macro.
<done>
∂12-Oct-87 1803 Moon@STONY-BROOK.SCRC.Symbolics.COM Object Creation Writeup
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 12 Oct 87 18:02:44 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 253739; Mon 12-Oct-87 21:03:43 EDT
Date: Mon, 12 Oct 87 21:03 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Object Creation Writeup
To: Common-Lisp-Object-System@sail.stanford.edu
Message-ID: <19871013010341.1.MOON@EUPHRATES.SCRC.Symbolics.COM>
Dick, this is the final draft of the Object Creation Writeup, unless
we send you any corrections on Tuesday.
-foo- means the word foo in italics. FOO means the word foo in boldface.
>>>> New Writing
Page 1-5 Creating Instances of Classes
[Replace existing text with this. The goal is to give an overview of
creating instances. It's too early to discuss initialization in detail
because we haven't discussed methods yet.]
The generic function MAKE-INSTANCE creates and returns a new instance of
a class. CLOS provides a flexible means for specifying how a new
instance is initialized. For example, users specify how to fill the
slots with values (either by giving an argument to MAKE-INSTANCE, or by
providing a default initial value). Users can also write methods that
perform extra initialization. The complete initialization protocol is
described in the section "Object Creation and Initialization".
Page 1-27: New Chapter: Object Creation and Initialization
SECTION: Overview
The function MAKE-INSTANCE creates and returns a new instance of a
class. The first argument is a class or the name of a class, and the
remaining arguments are an initarg ("initialization argument") list.
Initialization consists of several distinct steps, including: combining
the explicitly supplied initargs with the default values for the
unsupplied initargs, checking the validity of the initargs, allocating
storage for the instance, filling slots with values, and executing
user-supplied methods that perform additional initialization. CLOS
defines MAKE-INSTANCE in a procedural way, with each step represented by
a generic function. This gives the user the ability to customize any
number of the steps. In addition, MAKE-INSTANCE is a generic function,
allowing the user to replace the entire procedure if so inclined.
CLOS specifies default methods for each step, so there is a well-defined
standard behavior for the entire initialization procedure. For many
programs, the standard behavior is appropriate. The standard behavior
provides users with four simple mechanisms for controlling
initialization:
- Declaring a symbol to be an initarg for a slot, by
by using the :INITARG slot option. This allows one to
provide a value for a slot in a call to MAKE-INSTANCE.
- Supplying a default value form for an initarg, by using the
:DEFAULT-INITARGS class option. This default value is used if the
initarg is not explicitly provided as an argument to MAKE-INSTANCE.
- Supplying a default value form for a slot, by using the :INITFORM
slot option. This default value is stored into the slot if no
initarg associated with that slot is given as an argument to
MAKE-INSTANCE or defaulted by :DEFAULT-INITARGS.
- Defining methods for INITIALIZE-INSTANCE. The slot-filling
behavior described above is implemented by a system-supplied
default method for INITIALIZE-INSTANCE. When users need
to exert greater control over initialization, they can provide
methods for INITIALIZE-INSTANCE. In most cases :AFTER methods
are appropriate for this purpose, because they are called
after the default method that fills the slots, and thus do not
override the normal slot-filling behavior.
Note that the object creation and initialization procedure can be
controlled at two different levels. The standard behavior offers the
four mechanisms mentioned above; this level can be considered the
Programmer Interface level. At the Meta-object level, users can exert
greater control over each step of this procedure; this level can be
considered the interface for experimentation with alternative
object-oriented paradigms.
There is one general guideline that distinguishes between the Programmer
Interface level and the Meta-object levels of programming. To customize
behavior at the Programmer Interface level, the user defines methods
that specialize on instances. That is, the arguments that select
methods are instances. To customize behavior at the Meta-object level,
the user defines methods that specialize on classes. That is, the
arguments that select methods are classes.
This chapter begins by describing the terminology and concepts of the
standard initialization behavior, which is the Programmer Interface.
This chapter then describes the procedural definition of MAKE-INSTANCE.
It briefly mentions the generic functions that implement each step of
the procedure; this is the Meta-object level of initialiation. The
details of these functions are documented in Chapter 3.
SECTION: Terminology Related to Object Creation and Initialization
The terminology related to object creation and initialization is
presented here:
-initarg-. An initarg (initialization argument) is a keyword argument
that can be used to control object creation and initialization. The
&key arguments to MAKE-INSTANCE are initargs. It is often convenient to
use keyword symbols to name initargs, but the name of an initarg can be
any symbol, including NIL. There are two possible purposes for an
initarg: to fill a slot with a value or to provide an argument for
an initialization method. A single initarg can be used for more than
one purpose.
-initarg list-. An initarg list (initialization argument list) is a
list of alternating initarg names and values. Its structure is
identical to a property list and also identical to the portion of an
argument list processed for &key parameters. As in those lists, if an
initarg name appears more than once in an initarg list, the leftmost
occurrence supplies the value and the remaining occurrences are ignored.
The arguments to MAKE-INSTANCE (after the first argument) are an initarg
list. As in an &key argument list, :ALLOW-OTHER-KEYS can appear in an
initarg list, and if its value is non-NIL, error-checking of initarg
names is disabled.
-slot-filling initarg-. An initarg associated with a slot. If
the initarg has a value in the initarg list, the value is stored into
the slot of the newly-created object, overriding any initform associated
with the slot. A single initarg can fill more than one slot. A
slot-filling initarg that fills a shared slot stores its value into the
shared slot, replacing any previous value.
-method-implemented initarg-. An initarg associated with a method. A
method-implemented initarg is intended as an argument for one or more
methods for INITIALIZE-INSTANCE or ALLOCATE-INSTANCE. When an object is
created, the method is called with the initarg's value as an argument
and the method uses the value however it chooses. If the initarg has no
value in the initarg list, the method's lambda-list supplies a default
value.
SECTION: Declaring the Validity of Initargs
MAKE-INSTANCE checks the validity of the initargs and signals an error
if an initarg is supplied that is not valid. An initarg is declared
as valid in the same place where its purpose (whether slot-filling or
method-implemented) is stated.
Slot-filling initargs are declared as valid by the :INITARG slot option
to DEFCLASS. The :INITARG slot option is inherited from superclasses.
Thus, the set of valid slot-filling initargs for a class is the union of
the initargs declared by the class and its superclasses.
Method-implemented initargs are declared as valid by defining methods
for INITIALIZE-INSTANCE or ALLOCATE-INSTANCE. The keyword name of each
keyword parameter specifier in the method's lambda-list becomes a
method-implemented initarg for all classes for which this method is
applicable. Thus, method inheritance controls the set of valid
method-implemented initargs.
The set of valid initargs for a class is the union of the valid
slot-filling initargs, the valid method-implemented initargs, and the
pre-defined initarg :ALLOW-OTHER-KEYS. The default for
:ALLOW-OTHER-KEYS is NIL, and its specification is the same as Common
Lisp defines for &KEY argument lists.
SECTION: Defaulting of Initargs
A -default value form- can be supplied for an initarg. The way to
provide a default value form for either a slot-filling and
method-implemented initarg is to use the :DEFAULT-INITARGS class option.
A default value form is usually specified by a different class from the
class that declared the initarg as valid. Thus, :DEFAULT-INITARGS is
usually used to supply a default value for an inherited initarg.
The :DEFAULT-INITARGS class option is inherited. See ``Inheritance of
Class Options''.
The :DEFAULT-INITARGS class option is followed by alternating initarg
names and forms. Each form is the default value form for the
corresponding initarg. The default value form of an initarg is used
only if that initarg does not appear in the arguments to MAKE-INSTANCE.
In that case, the default value form is evaluated in the lexical
environment of the DEFCLASS form that supplied it, and the resulting
value is used as the initarg's value. The initarg name and value are
appended to the initarg list supplied to MAKE-INSTANCE. The result is
a -defaulted initarg list- in which the explicitly supplied initargs
appear before the defaulted initargs. Defaulted initargs are ordered
according to the order in the class precedence list of the classes
that supplied the default values.
The :DEFAULT-INITARGS option is used only to provide default values for
initargs; it does not declare a symbol as a valid initarg name.
One should distinguish between the purposes of :DEFAULT-INITARGS and
:INITFORM, with respect to slot-filling initargs. The
:DEFAULT-INITARGS class option allows the user to give a default value
form for an initarg without knowing whether or not the initarg fills a
slot. If that initarg is not explicitly supplied in a call to
MAKE-INSTANCE, the default value form is used, just as if it had been
supplied in the call. In contrast, the :INITFORM slot option allows
the user to give a default initial value form for a slot. An :INITFORM
is used only if no initarg associated with that slot is given as an
argument to MAKE-INSTANCE or defaulted by :DEFAULT-INITARGS. The two
kinds of defaulting exist at different levels of abstraction.
Note: CLOS does not guarantee any given order of evaluation of
default-initarg forms and initforms. If there are dependencies among
these forms, INITIALIZE-INSTANCE methods should be used instead. In
most programs, the initforms and default-initarg forms are either
constants or simple forms that construct new objects; forms with
side-effects are permitted, but are not typically used.
SECTION: Rules for Duplication of Initargs
The following rules specify what happens when initargs are duplicated in
various ways.
- The :INITARG slot option may be specified more than once for a given slot.
- A single initarg can initialize more than one slot if the same initarg name
appears in more than one :INITARG slot option.
- It is valid for a given initarg name to be defined more than once as a
slot-filling initarg, as a method-implemented initarg, or both.
- If two initargs that initialize the same slot, with the same or different
names, are given in the arguments to MAKE-INSTANCE, the leftmost of these
initargs in the initarg list prevails. This behavior is consistent
with the behavior of property lists and the portion of an argument
list processed for &key parameters.
- If two different initargs that initialize the same slot have default values,
and neither is given explicitly in the arguments to MAKE-INSTANCE,
the initarg that appears in a :DEFAULT-INITARGS slot option in the most
specific class prevails, or if they appeared in the same class, the one whose
mention in :DEFAULT-INITARGS is leftmost in the DEFCLASS form prevails.
During the defaulting of initargs, the defaults are appended
to the end of the initarg list in this order.
- If there are two different initargs that initialize the same slot, and one
was given explicitly in the arguments to MAKE-INSTANCE while the other was
defaulted via :DEFAULT-INITARGS, the explicit one prevails. (This rule is
implied by the two preceding rules, but it is worth mentioning
explicitly.)
- If a slot has both an :INITFORM and an :INITARG slot option, and the
slot-filling initarg is defaulted via :DEFAULT-INITARGS, the initform is not
used and is not evaluated.
An illustrative example of the above rules:
(defclass a () ((x :initarg a)))
(defclass b (a) ((x :initarg b))
(:default-initargs a 1 b 2))
DEFAULTED
FORM INITARG LIST CONTENTS OF X SLOT
(make-instance 'b) (a 1 b 2) 1
(make-instance 'b 'a 3) (a 3 b 2) 3
(make-instance 'b 'b 4) (b 4 a 1) 4
(make-instance 'b 'a 1 'a 2) (a 1 a 2 b 2) 1
SECTION: Methods for INITIALIZE-INSTANCE
INITIALIZE-INSTANCE is a generic function that uses standard method
combination. Users can define methods for INITIALIZE-INSTANCE to
perform any initialization that cannot be achieved with the simple
slot-filling mechanisms.
CLOS calls the generic function INITIALIZE-INSTANCE after it has:
- Computed the defaulted initarg list by combining the
supplied initarg list with any default initargs
for the class.
- Checked the validity of the defaulted initarg list. If any
of the initargs has not been declared as valid, an error is
signaled.
- Created a blank instance.
CLOS then calls INITIALIZE-INSTANCE with the blank instance and the
defaulted initarg list. The system-supplied default method is a
primary method that initializes the slots with values according to the
initarg list. For each slot (whether local or shared):
- If an initarg in the defaulted initarg list fills that slot, its
value is stored into the slot. (This is true even if a :BEFORE method
has modified the slot.)
- Otherwise, if the slot is uninitialized and it has an initform, the
initform is evaluated and the result is stored into the slot.
- The duplicate-resolution rules mentioned in the section "Rules for
Duplication of Initargs" are obeyed.
Typically, user-defined methods are :AFTER methods; however that is not
a requirement. Users should take care not to supply primary methods
that override the default primary method unless they want to prevent
the normal slot-filling from occurring.
CLOS provides two functions that are useful in the bodies of
INITIALIZE-INSTANCE methods. The function SLOT-BOUNDP returns a
boolean value that states whether the slot is bound or not; this allows
for writing :AFTER methods for INITIALIZE-INSTANCE that initialize slots
only if they have not already been initialized. The function
SLOT-MAKUNBOUND restores a slot to the uninitialized condition.
Implementations are permitted to make certain optimizations of
INITIALIZE-INSTANCE. The description of INITIALIZE-INSTANCE in Chapter
2 mentions the possible optimizations. One possible optimization has
the following impact on user-supplied methods: :BEFORE and :AROUND
methods for INITIALIZE-INSTANCE cannot rely on all the slots being
uninitialized.
SECTION: Procedural Definition of MAKE-INSTANCE
MAKE-INSTANCE behaves as if it were defined as follows, except that
certain optimizations are permitted:
(defmethod make-instance ((class standard-class) &rest initargs)
(setq initargs (default-initargs class initargs))
(check-initargs class initargs)
(let ((instance (apply #'allocate-instance class initargs)))
(apply #'initialize-instance instance initargs)
instance))
(defmethod make-instance ((class-name symbol) &rest initargs)
(apply #'make-instance (symbol-class class-name) initargs))
Users can customize this procedure at either the Programmer Interface
level, the Meta-object level, or both.
The Programmer Interface level includes using the :INITFORM, :INITARG,
and :DEFAULT-INITARGS options to DEFCLASS, and defining methods for
INITIALIZE-INSTANCE.
The Meta-object level supports extra customization by defining methods
for: DEFAULT-INITARGS, CHECK-INITARGS, and ALLOCATE-INSTANCE.
Chapter 3 documents each of these generic functions and the
system-supplied default methods.
As noted above, certain optimizations of the MAKE-INSTANCE procedure are
permitted. The description of INITIALIZE-INSTANCE in Chapter 2 mentions
some possible optimizations to this procedure. Additional
optimizations are possible, including inlining and constant-folding of
method lookup and method bodies, provided that the programming
environment either prohibits redefining these methods or updates
everything when they are redefined. One approach might be for
MAKE-INSTANCE to have a separate method for every class, which is
automatically written and compiled by the system.
Because of optimization, methods for the meta-object generic functions
listed may not actually be called on every call to MAKE-INSTANCE, or may
not receive exactly the arguments that would be expected. For example,
CHECK-INITARGS might actually be called before DEFAULT-INITARGS rather
than after, if it has already been determined that the default initargs
will pass CHECK-INITARGS.
>>>> Mechanical Tasks:
Page 1-8: inheritance of :initarg
The :INITARG slot-option is inherited from superclasses. The set of
initargs that initialize a given slot is the union of the sets of initargs declared
in :INITARG slot-options with the same slot name in the class and its
superclasses.
Page-9: inheritance of :default-initargs (the only class option that is
inherited)
The :DEFAULT-INITARGS class option is inherited; the set of initargs for
a class that are defaulted is the union of the sets of initargs
specified in :DEFAULT-INITARGS class options of the class and its
superclasses. When more than one default value form is supplied for a
given initarg, the default value form supplied by the class that appears
earliest in the class precedence list is used.
Page 1-21: Congruent Lambda-lists for All Methods of a Generic Function
Replace the old rules with the new ones.
Probably should add a note about on 1-21 about this:
The proposal assumes CL-Cleanup issue KEYWORD-ARGUMENT-NAME-PACKAGE:ANY, which
stated that the names of &key arguments do not have to be keyword symbols.
The terminology of CLtL is used for discussing keyword arguments, but it
should be understood that keyword names are not necessarily symbols in
the keyword package; that's just a default convention.
Page 2-15 (and onward) DEFCLASS section
Add :INITARG and :DEFAULT-INITARGS to the syntax diagram.
Add this info:
The :INITARG -name- slot-option -declares- an initarg named -name- and
-specifies- that this initarg initializes the slot to which the
slot-option is attached. -name- is any symbol. If the initarg has a
value, the value is stored into the slot and the slot's :INITFORM, if
any, is -not- evaluated. If no initarg specified to initialize a given
slot has a value, then the slot is initialized according to the
:INITFORM (if any). This slot option can appear any number of times.
The :DEFAULT-INITARGS option is followed by a list of alternating
initarg names and default-initarg forms. If one of these initargs does
not appear in the initarg list supplied to MAKE-INSTANCE, the
corresponding default-initarg form is evaluated, then the initarg name
and the form's value are added to the end of the initarg list. The form
is evaluated every time it is used. The lexical environment in which
this form is evaluated is the lexical environment in which DEFCLASS was
evaluated. The dynamic environment is the dynamic environment in which
MAKE-INSTANCE was called. The :DEFAULT-INITARGS option may be specified
more than once. However, an error is signaled if an initarg name
appears more than once in a single :DEFAULT-INITARGS option, or in more
than one :DEFAULT-INITARGS option for a single class.
>>>> Add descriptions of each of these functions to Chapter 2:
(MAKE-INSTANCE -class- &key -initargs-...) => -instance-
Users call this function to create objects. Class can be either a class or
the name of a class. Meta-users can define new methods for MAKE-INSTANCE
to replace the object-creation protocol. For details, see
the section "Object Creation and Initialization".
(INITIALIZE-INSTANCE instance &key &allow-other-keys)
MAKE-INSTANCE calls this with the freshly-created instance, any initargs that
were supplied to MAKE-INSTANCE, and any defaulted initargs. Users define
methods for this to create method-implemented initargs. Typically,
user-defined methods are :AFTER methods, however that is not a requirement.
The primary method for INITIALIZE-INSTANCE is system-supplied and takes care
of the slot-filling initargs. For each slot (whether local or shared):
- if an initarg was specified or defaulted that fills that slot, its
value is stored into the slot. (This is true even if a :BEFORE method
has modified the slot.)
- otherwise, if the slot is uninitialized and it has an initform, the
initform is evaluated and the result is stored into the slot.
- the duplicate-resolution rules mentioned in the section "Rules for
Duplication of Initargs" are obeyed.
Implementations are permitted to optimize initforms that neither
produce nor depend on side-effects, by evaluating them and storing them
into slots before running any INITIALIZE-INSTANCE methods, rather than
handling them in the primary INITIALIZE-INSTANCE method. (This might be
implemented by having the ALLOCATE-INSTANCE method copy a prototype
instance.)
Implementations are permitted to optimize default value forms for
slot-filling initargs by not actually consing the complete initarg list,
when the only method that would see the complete list is the
system-supplied primary method, e.g. when no other methods use &REST.
In this case default value forms can be treated like initforms. This
has no visible effects other than a performance improvement.
(SLOT-BOUNDP instance slot-name) => boolean
Allows writing INITIALIZE-INSTANCE :AFTER methods that only initialize slots if
they haven't been initialized already.
(SLOT-MAKUNBOUND instance slot-name) => instance
Restores a slot to the uninitialized condition.
>>>> Add descriptions of each of these functions to Chapter 3
>>> Functions underlying the tools
It is undefined what happens if you modify the values returned by any
of the functions in this section. It is permitted, but not required,
for an implementation to return values that share with internal data
structures. Some of these functions will be SETF'able; which ones
remain to be determined.
(CLASS-ALL-INITARGS class) => list of initarg names, including inherited
ones. This is (REDUCE #'UNION (MAPCAR #'CLASS-DIRECT-INITARGS cpl)).
(CLASS-DIRECT-INITARGS class) => list of initarg names. This works by
computing the applicable methods for ALLOCATE-INSTANCE and for
INITIALIZE-INSTANCE and examining their lambda-lists (using
METHOD-KEYWORD-NAMES), then combining that with the class's list of
slot-filling initargs.
(CLASS-ALL-INITARG-DEFAULTS class)
=> ((initarg-name default-value-function default-value-form)...)
(CLASS-DIRECT-INITARG-DEFAULTS class)
=> ((initarg-name default-value-function default-value-form)...)
This reflects the :DEFAULT-INITARGS option. Default-value-form is the form
that was originally specified, and is retained purely for explanatory
purposes. default-value-function is what gets actually called; its effect is
equivalent to enclosing default-value-form in the appropriate lexical
environment. Default-value-function takes no arguments.
(CLASS-ALL-SLOT-INITARGS class) => ((initarg-name slot-name...)...)
(CLASS-DIRECT-SLOT-INITARGS class) => ((initarg-name slot-name...)...)
This reflects the :INITARG slot-option.
(COMPUTE-APPLICABLE-METHODS generic argument-list) => list of methods
(METHOD-KEYWORD-NAMES method) => list of symbols or &ALLOW-OTHER-KEYS,
indicating the keyword names of the keyword parameter specifiers in
the method's lambda-list. The result is the symbol &ALLOW-OTHER-KEYS
instead of a list if the method's lambda-list contains that symbol.
>>> Meta-object functions
(ALLOCATE-INSTANCE class &key &allow-other-keys) => instance
Meta-users can replace the system-supplied, implementation-dependent method
for this. Any keyword arguments accepted by applicable ALLOCATE-INSTANCE
methods become valid initargs.
(CHECK-INITARGS class initarg-list)
Meta-users could replace the system-supplied method that implements the
normal rules for initarg validity.
(DEFAULT-INITARGS class initarg-list) => initarg-list
The system-supplied method implements the :DEFAULT-INITARGS class option
by appending initargs that do not appear in initarg-list to the end
of the returned list. The initarg-list supplied as an argument is not
modified. The order of initargs appended to the list is determined by
the duplicate-initarg rules listed earlier.
(FINALIZE-INHERITANCE class &key slots methods initargs)
This is called by the system at least once before a class is instantiated, and
is called again whenever anything relevant changes. System-supplied methods
for this conspire with methods for CHECK-INITARGS, etc., to make MAKE-INSTANCE
faster. Users with their own optimization needs can add methods for this
generic function that will precompute things based on inherited information,
and update the precomputed information whenever anything changes.
The :slots, :methods, and :initargs arguments are booleans that are true
when the specified type of inheritance needs to be recomputed.
<done>
∂13-Oct-87 1412 skeene@STONY-BROOK.SCRC.Symbolics.COM the new DEFMETHOD syntax
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 13 Oct 87 14:12:01 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 254530; Tue 13-Oct-87 17:12:52 EDT
Return-path: <@[10.0.0.11],@SAIL.STANFORD.EDU:skeene@Riverside.SCRC.Symbolics.COM>
Received: from SAIL.STANFORD.EDU ([10.0.0.11]) by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 239887; 23 Sep 87 15:44:38 EDT
Received: from SCRC-RIVERSIDE.ARPA by SAIL.STANFORD.EDU with TCP; 23 Sep 87 12:40:32 PDT
Received: from JUNCO.SCRC.Symbolics.COM by Riverside.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 168478; Wed 23-Sep-87 14:35:02 EDT
Date: Wed, 23 Sep 87 14:35 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: the new DEFMETHOD syntax
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <870923143539.1.SKEENE@JUNCO.SCRC.Symbolics.COM>
Resent-To: rpg@sail.stanford.edu, lgd@sail.stanford.edu
Resent-From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Resent-Date: Tue, 13 Oct 87 17:12 EDT
Resent-Message-ID: <871013171205.8.SKEENE@JUNCO.SCRC.Symbolics.COM>
Resent-Comments: here's material for the spec
This message reflects the decisions made last week to change DEFMETHOD
syntax to "refer to" each specialized parameter, and to use EQL instead
of QUOTE for individual methods.
The changes to DEFMETHOD syntax require the following changes to the
specification:
p 2-34: add this to Remarks:
The DEFMETHOD macro ``refers to'' each specialized parameter (see the
description of IGNORE in Common Lisp: the Language, page 160). This
includes parameters that specialize on T. This means that a compiler
warning does not occur whether or not the body of the method refers to a
specialized parameter. Note that a parameter that specializes on T is
not synonymous with an unspecialized parameter in this context.
p 2-33, in Syntax: Change (QUOTE <datum>) to (EQL <form>)
p 2-34, second paragraph: Change (QUOTE <object>) to (EQL <form>)
p 1-20, second bullet: Change (QUOTE <object>) to (EQL <form>)
p 1-20, replace first paragraph with this:
A parameter specializer name denotes a parameter specializer as follows:
Let N be a parameter specializer name and P be the corresponding
parameter specializer. If N is a class name, then P is the class with
that name. If N is (EQL <form>), then P is (EQL <object>), where <object>
is the result of evaluating <form>.
p 1-20, fifth paragraph: Change (QUOTE <object>) to (EQL <object>)
p 1-20, seventh paragraph: Change (QUOTE <object>) to (EQL <object>)
p 1-20, seventh paragraph: Replace last two sentences with:
The only parameter specializer that can be a list is (EQL <object>). This
proposal requires that Common Lisp be modified to include (DEFTYPE EQL
(<object>) `(MEMBER ,<object>)).
p 1-21, first paragraph: Remove last sentence, and replace it with a
new paragraph:
For method combination types defined by the short form of
DEFINE-METHOD-COMBINATION and the built-in method combination types, a
primary method has the name of the method combination type as its sole
qualifier. These method combination types also support auxiliary
methods, which have :AROUND as their sole qualifier.
<done>
∂13-Oct-87 1412 skeene@STONY-BROOK.SCRC.Symbolics.COM draft of built-in method combination types
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 13 Oct 87 14:12:22 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 254533; Tue 13-Oct-87 17:13:16 EDT
Return-path: <@[10.0.0.11],@SAIL.STANFORD.EDU:skeene@STONY-BROOK.SCRC.Symbolics.COM>
Received: from SAIL.STANFORD.EDU ([10.0.0.11]) by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 239391; 23 Sep 87 07:30:50 EDT
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 23 Sep 87 04:27:16 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 239385; Wed 23-Sep-87 07:28:16 EDT
Date: Wed, 23 Sep 87 07:27 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: draft of built-in method combination types
To: common-lisp-object-system@SAIL.STANFORD.EDU
Message-ID: <870923072736.4.SKEENE@JUNCO.SCRC.Symbolics.COM>
Resent-To: rpg@sail.stanford.edu, lgd@sail.stanford.edu
Resent-From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Resent-Date: Tue, 13 Oct 87 17:13 EDT
Resent-Message-ID: <871013171306.9.SKEENE@JUNCO.SCRC.Symbolics.COM>
Resent-Comments: here's material for the spec
In September we agreed that CLOS should provide some built-in method
combination types. Yesterday Dave and I chose the most generally
useful ones that Flavors offers. The following text is a draft of a
new section to be added to Chapter 1, after "Declarative Method
Combination". UPPERCASE means bold, and <this> means italic.
Comments are welcomed.
-------------------------------------------------------------------
Built-in Method Combination Types
CLOS provides a set of built-in method combination types. To specify
that a generic function should use one of these method combination
types, give the name of the method combination as the argument to
the :METHOD-COMBINATION option to DEFGENERIC or GENERIC-FUNCTION.
These method combination types act as though they were defined by the
short form of DEFINE-METHOD-COMBINATION. They recognize two roles for
methods.
An :AROUND method has the keyword symbol :AROUND as its sole
qualifier. :AROUND methods work just as they do in standard method
combination. CALL-NEXT-METHOD is supported in :AROUND methods only.
A primary method has the name of the method combination type as its
sole qualifier. For example, the method combination type AND
recognizes methods whose sole qualifier is AND; these are primary
methods.
Each of these method combination types is named after a Lisp operator,
which can be a function, special form, or macro. The effective method
combines all of the applicable primary methods in a call to the Lisp
operator with the same name as the method combination type. That is,
the method combination type produces a Lisp form (<operator> <method-call>
<method-call> ...).
Names of built-in
method combination types
+
AND
APPEND
LIST
MAX
MIN
NCONC
OR
PROGN
The semantics of these types of method combination are:
If there are any :AROUND methods, the most specific :AROUND method is
called. It supplies the value or values of the generic function.
Inside the body of an :AROUND method, CALL-NEXT-METHOD can be used to
immediately call the next method. When the next method returns, the
:AROUND method can execute more code, perhaps based on the returned
value or values. By convention, :AROUND methods almost always use
CALL-NEXT-METHOD.
If an :AROUND method invokes CALL-NEXT-METHOD, the next most specific
:AROUND method is called, if one is applicable. If there are no :AROUND
methods or if CALL-NEXT-METHOD is called by the least specific :AROUND
method, the Lisp operator corresponding to the method combination type
is called. The arguments to that operator include the value or values
returned by each of the applicable primary methods. By default the
order of the primary methods is :MOST-SPECIFIC-FIRST. However, the
order can be reversed by supplying :MOST-SPECIFIC-LAST as the second
argument to the :METHOD-COMBINATION option.
An error is signaled if CALL-NEXT-METHOD is used in a primary method.
An error is signaled if there are no applicable primary methods.
These types of method combination require exactly one qualifier per
method. An error is signalled if there are applicable methods with no
qualifiers, or with qualifiers that are not supported by the method
combination type.
[Note: also need to add the preceding paragraph to page 2-27, in the
discussion of short form of DEFINE-METHOD-COMBINATION.]
∂14-Oct-87 0827 @STONY-BROOK.SCRC.Symbolics.COM,@JUNCO.SCRC.Symbolics.COM:skeene@STONY-BROOK.SCRC.Symbolics.COM status of "object" or "standard-object"
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 14 Oct 87 08:27:26 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via INTERNET with SMTP id 255053; 14 Oct 87 11:28:07 EDT
Date: Wed, 14 Oct 87 11:27 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: status of "object" or "standard-object"
To: common-lisp-object-system@sail.stanford.edu
Message-ID: <871014112750.2.SKEENE@JUNCO.SCRC.Symbolics.COM>
Last month we discussed whether CLOS should specify the class "object"
or "standard-object", and we didn't get anywhere.
To me, this seems to be a hole in the spec that we ought to fill up in
time for the next draft. It seems like most people believe there will
be one or more of these classes, but the spec doesn't say anything at
all about them. Unless we do something, our draft will imply that
there won't be these classes, but we will still be assuming there will
be.
The spec excludes these classes quite explicitly, in the CPL examples.
The class precedence lists include all the user-defined classes and T,
but nothing else. Also, the section on Meta Objects makes no mention
of "object" or "standard-object".
We could either make a decision on this, or include it in the spec under
a new section "Issues still under Discussion". It might happen that
other issues will have the same uncertain status at the November
deadline. Constructors are presently in that category as well.
<done>
∂14-Oct-87 1026 @Score.Stanford.EDU:kempf%hplabsz@hplabs.HP.COM Re: Status (and TRACE-EXECUTION spec)
Received: from SCORE.STANFORD.EDU by SAIL.STANFORD.EDU with TCP; 14 Oct 87 10:25:57 PDT
Received: from hplabs.HP.COM (hplabs.hpl.hp.com.#Internet) by SCORE.STANFORD.EDU with TCP; Wed 14 Oct 87 10:00:40-PDT
Received: from hplms2 by hplabs.HP.COM with SMTP ; Wed, 14 Oct 87 10:01:48 PDT
Received: from hplabsz.hpl.hp.com by hplms2; Wed, 14 Oct 87 13:01:26 edt
Return-Path: <kempf@hplabsz>
Received: from hplabsz by hplabsz; Wed, 14 Oct 87 10:00:42 pdt
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
Cc: common-lisp-object-system@SAIL.Stanford.EDU
Subject: Re: Status (and TRACE-EXECUTION spec)
X-Mailer: mh6.5
In-Reply-To: Your message of 13 Oct 87 14:27:00 -0700.
Date: Wed, 14 Oct 87 10:00:36 MDT
Message-Id: <3026.561225636@hplabsz>
From: kempf%hplabsz@hplabs.HP.COM
>
> LGD and I are working (like mad) on the spec. I am concentrating
> on the concepts chapter and Linda on the functions chapter.
> This will require very fast turnaround from you folks on the draft.
Ok, let us know if you need anything else.
I haven't posted an updated draft of the TRACE-EXECUTION generic function
yet, since it wasn't clear from the last meeting whether it was in
the same category as PRINT-OBJECT, and therefore should go in Section 2,
or was a Cleanup Committee issue. Clearly, the modifications to TRACE
are a Cleanup Committee issue. In any event, below is the text of the
TRACE-EXECUTION generic function spec I presented at the September meeting,
in case it should go in Section 2.
jak
Uppercase indicates BOLD, _this_ indicates italic
-------------------------------------------------------------------------------
TRACE-EXECUTION _object_ &KEY :ENVIRONMENT :BREAK _[Generic Function]_
TRACE-EXECUTION discriminates on _object_ to select an implementation
specific method that arranges for the executable entity associated
with _object_ to be traced. The :ENVIRONMENT keyword parameter is for
those implementations which require environmental information to
arrange for tracing to occur. Implementations are required to provide
TRACE-EXECUTION as the system level entry point for implementing TRACE
functionality. If the :BREAK keyword argument is not NIL, arrangement is
made for the BREAK function to be called after trace information is printed.
The exact nature and number of methods associated with TRACE-EXECUTION
will differ, depending on what executable entities can be specified
by TRACE, but every implementation needs to support methods which
dispatch on objects having the following classes:
SYMBOL-The function indicated by the symbol will be traced when invoked
in the environment.
METHOD-The method function is traced when invoked.
GENERIC-FUNCTION-The generic function is traced when the discriminator
code is invoked.
Implementations are encouraged to provide as many methods as is possible.
>>>> Mechanical Tasks:
* Page 1-8: inheritance of :initarg
The :INITARG slot-option is inherited from superclasses. The set of
initargs that initialize a given slot is the union of the sets of initargs declared
in :INITARG slot-options with the same slot name in the class and its
superclasses.
* Page-9: inheritance of :default-initargs (the only class option that is
inherited)
The :DEFAULT-INITARGS class option is inherited; the set of initargs for
a class that are defaulted is the union of the sets of initargs
specified in :DEFAULT-INITARGS class options of the class and its
superclasses. When more than one default value form is supplied for a
given initarg, the default value form supplied by the class that appears
earliest in the class precedence list is used.
* Page 1-21: Congruent Lambda-lists for All Methods of a Generic Function
Replace the old rules with the new ones.
[No - rpg
Probably should add a note about on 1-21 about this:
The proposal assumes CL-Cleanup issue KEYWORD-ARGUMENT-NAME-PACKAGE:ANY, which
stated that the names of &key arguments do not have to be keyword symbols.
The terminology of CLtL is used for discussing keyword arguments, but it
should be understood that keyword names are not necessarily symbols in
the keyword package; that's just a default convention.]
Functi Things
Page 2-15 (and onward) DEFCLASS section
Add :INITARG and :DEFAULT-INITARGS to the syntax diagram.
Add this info:
The :INITARG -name- slot-option -declares- an initarg named -name- and
-specifies- that this initarg initializes the slot to which the
slot-option is attached. -name- is any symbol. If the initarg has a
value, the value is stored into the slot and the slot's :INITFORM, if
any, is -not- evaluated. If no initarg specified to initialize a given
slot has a value, then the slot is initialized according to the
:INITFORM (if any). This slot option can appear any number of times.
The :DEFAULT-INITARGS option is followed by a list of alternating
initarg names and default-initarg forms. If one of these initargs does
not appear in the initarg list supplied to MAKE-INSTANCE, the
corresponding default-initarg form is evaluated, then the initarg name
and the form's value are added to the end of the initarg list. The form
is evaluated every time it is used. The lexical environment in which
this form is evaluated is the lexical environment in which DEFCLASS was
evaluated. The dynamic environment is the dynamic environment in which
MAKE-INSTANCE was called. The :DEFAULT-INITARGS option may be specified
more than once. However, an error is signaled if an initarg name
appears more than once in a single :DEFAULT-INITARGS option, or in more
than one :DEFAULT-INITARGS option for a single class.
>>>> Add descriptions of each of these functions to Chapter 2:
(MAKE-INSTANCE -class- &key -initargs-...) => -instance-
Users call this function to create objects. Class can be either a class or
the name of a class. Meta-users can define new methods for MAKE-INSTANCE
to replace the object-creation protocol. For details, see
the section "Object Creation and Initialization".
(INITIALIZE-INSTANCE instance &key &allow-other-keys)
MAKE-INSTANCE calls this with the freshly-created instance, any initargs that
were supplied to MAKE-INSTANCE, and any defaulted initargs. Users define
methods for this to create method-implemented initargs. Typically,
user-defined methods are :AFTER methods, however that is not a requirement.
The primary method for INITIALIZE-INSTANCE is system-supplied and takes care
of the slot-filling initargs. For each slot (whether local or shared):
- if an initarg was specified or defaulted that fills that slot, its
value is stored into the slot. (This is true even if a :BEFORE method
has modified the slot.)
- otherwise, if the slot is uninitialized and it has an initform, the
initform is evaluated and the result is stored into the slot.
- the duplicate-resolution rules mentioned in the section "Rules for
Duplication of Initargs" are obeyed.
Implementations are permitted to optimize initforms that neither
produce nor depend on side-effects, by evaluating them and storing them
into slots before running any INITIALIZE-INSTANCE methods, rather than
handling them in the primary INITIALIZE-INSTANCE method. (This might be
implemented by having the ALLOCATE-INSTANCE method copy a prototype
instance.)
Implementations are permitted to optimize default value forms for
slot-filling initargs by not actually consing the complete initarg list,
when the only method that would see the complete list is the
system-supplied primary method, e.g. when no other methods use &REST.
In this case default value forms can be treated like initforms. This
has no visible effects other than a performance improvement.
(SLOT-BOUNDP instance slot-name) => boolean
Allows writing INITIALIZE-INSTANCE :AFTER methods that only initialize slots if
they haven't been initialized already.
(SLOT-MAKUNBOUND instance slot-name) => instance
Restores a slot to the uninitialized condition.
>>>> Add descriptions of each of these functions to Chapter 3
>>> Functions underlying the tools
It is undefined what happens if you modify the values returned by any
of the functions in this section. It is permitted, but not required,
for an implementation to return values that share with internal data
structures. Some of these functions will be SETF'able; which ones
remain to be determined.
(CLASS-ALL-INITARGS class) => list of initarg names, including inherited
ones. This is (REDUCE #'UNION (MAPCAR #'CLASS-DIRECT-INITARGS cpl)).
(CLASS-DIRECT-INITARGS class) => list of initarg names. This works by
computing the applicable methods for ALLOCATE-INSTANCE and for
INITIALIZE-INSTANCE and examining their lambda-lists (using
METHOD-KEYWORD-NAMES), then combining that with the class's list of
slot-filling initargs.
(CLASS-ALL-INITARG-DEFAULTS class)
=> ((initarg-name default-value-function default-value-form)...)
(CLASS-DIRECT-INITARG-DEFAULTS class)
=> ((initarg-name default-value-function default-value-form)...)
This reflects the :DEFAULT-INITARGS option. Default-value-form is the form
that was originally specified, and is retained purely for explanatory
purposes. default-value-function is what gets actually called; its effect is
equivalent to enclosing default-value-form in the appropriate lexical
environment. Default-value-function takes no arguments.
(CLASS-ALL-SLOT-INITARGS class) => ((initarg-name slot-name...)...)
(CLASS-DIRECT-SLOT-INITARGS class) => ((initarg-name slot-name...)...)
This reflects the :INITARG slot-option.
(COMPUTE-APPLICABLE-METHODS generic argument-list) => list of methods
(METHOD-KEYWORD-NAMES method) => list of symbols or &ALLOW-OTHER-KEYS,
indicating the keyword names of the keyword parameter specifiers in
the method's lambda-list. The result is the symbol &ALLOW-OTHER-KEYS
instead of a list if the method's lambda-list contains that symbol.
>>> Meta-object functions
(ALLOCATE-INSTANCE class &key &allow-other-keys) => instance
Meta-users can replace the system-supplied, implementation-dependent method
for this. Any keyword arguments accepted by applicable ALLOCATE-INSTANCE
methods become valid initargs.
(CHECK-INITARGS class initarg-list)
Meta-users could replace the system-supplied method that implements the
normal rules for initarg validity.
(DEFAULT-INITARGS class initarg-list) => initarg-list
The system-supplied method implements the :DEFAULT-INITARGS class option
by appending initargs that do not appear in initarg-list to the end
of the returned list. The initarg-list supplied as an argument is not
modified. The order of initargs appended to the list is determined by
the duplicate-initarg rules listed earlier.
(FINALIZE-INHERITANCE class &key slots methods initargs)
This is called by the system at least once before a class is instantiated, and
is called again whenever anything relevant changes. System-supplied methods
for this conspire with methods for CHECK-INITARGS, etc., to make MAKE-INSTANCE
faster. Users with their own optimization needs can add methods for this
generic function that will precompute things based on inherited information,
and update the precomputed information whenever anything changes.
The :slots, :methods, and :initargs arguments are booleans that are true
when the specified type of inheritance needs to be recomputed.
<done>
∂15-Oct-87 1451 Moon@YUKON.SCRC.Symbolics.COM Initialization
Received: from SCRC-YUKON.ARPA by SAIL.STANFORD.EDU with TCP; 15 Oct 87 14:51:23 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by YUKON.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 277369; Thu 15-Oct-87 17:52:02 EDT
Date: Thu, 15 Oct 87 17:52 EDT
From: Moon@STONY-BROOK.SCRC.Symbolics.COM, SKeene@STONY-BROOK.SCRC.Symbolics.COM
Sender: Moon@STONY-BROOK.SCRC.Symbolics.COM
Subject: Initialization
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
In-Reply-To: The message of 15 Oct 87 15:20 EDT from Dick Gabriel <RPG@SAIL.Stanford.EDU>,
The message of 15 Oct 87 15:23 EDT from Dick Gabriel <RPG@SAIL.Stanford.EDU>
Message-ID: <19871015215205.0.MOON@EUPHRATES.SCRC.Symbolics.COM>
The rewording to eliminate abbreviations and the "slot-filling"
and "method-implemented" terms seems to have worked out okay.
It makes the document a little longer, but that doesn't seem to
hurt understandability.
The former "terminology" section doesn't need bullets, it can just
be ordinary paragraphs. This section could be titled "Initialization
Arguments".
Comments on excerpts from the document. Note: some of these errors
were in the document we sent you; we didn't try to distinguish old
from new.
Content errors:
\item{\bull} Otherwise, if the slot has an {\bf :initform} form, that form
is evaluated and the result is stored into the slot.
--> This is >only< done if the slot is uninitialized, according to what
we agreed on. A :before method could store into the slot, and in that
case the :initform would not override it, even though an initialization
argument would override it. Slightly strange, but it's what the group
converged on.
the initialization argument that appears
in a {\bf :default-initargs} slot option in the most specific class
prevails, or if they appeared in the same class, the one whose mention is
leftmost in the {\bf :default-initargs} slot option in the {\bf defclass}
form prevails.
--> "more specific" would be clearer than "most specific" I think, since
"most specific" might be misunderstood to mean the very first class in the
CPL.
--> the part of this sentence applying when the two initargs are defaulted
by the same class got slightly mangled. Since :default-initargs can appear
more than once in a defclass, we have to say leftmost in the defclass
rather than leftmost in the option. Also this says "slot option" where
it means "class option", twice in this sentence.
Meta-object level supports extra customization by defining methods for:
{\bf default-initargs}, {\bf check-initargs}, and {\bf allocate-instance}.
--> add {\bf make-instance} to this list.
Style improvements:
The result is a {\bit defaulted initialization
argument list} in which the explicitly supplied initialization arguments
appear earlier in the list than the defaulted initialization arguments.
--> change "defaulted initialization arguments" to "initialization arguments
that were not explicitly supplied and were defaulted", or something that
means the same but is a little less verbose. The problem is an ambiguity
of whether "defaulted initialization arguments" means all the initargs
that have :default-initargs options, or just the ones that were actually
defaulted for this particular call to make-instance.
\item{\bull} It is valid for a given initialization argument name to be
defined more than once.
--> The term "defined" isn't defined. How about substituting:
\item{\bull} It is valid for a given initialization argument name to
appear both in an {\bf :initarg} slot option and in the lambda-list
of an initialization method.
\item{\bull} A blank instance is created.
--> The term "blank" is not defined. How about saying
\item{\bull} A new instance with uninitialized slots is created.
and then in the next sentence change "blank" to "new".
Should that be "uninitialized" or "unbound" slots or
"slots that have no values"?
(This
is true even if a {\bf :before} method has modified the slot.)
--> change "modified" to "stored a value in"
The initialization argument name
and value are appended to the initialization argument list supplied to
{\bf make-instance}. The result is a {\bit defaulted initialization
argument list} ...
--> This should be a new paragraph, and perhaps could be reordered to
start by saying that it produces the defaulted initialization arg list,
and then go on to say how it does it, instead of the reverse order.
The two kinds of defaulting exist at different levels
of abstraction.
--> If we're not going to explain "levels of abstraction" further,
maybe we should just delete this sentence.
Excerpts from the text in which I noticed typos:
provides a mechanism for to customizing each step.
--> for customizing
\item{\bull} A initialization argument can be associated with a slot.
--> An
the method is called with the initialization argument's
name and value as a named argument
--> as a keyword argument
(whether to fill
slot or to supply an argument to a method)
--> fill a slot
{bf :initform}
--> \bf
\item{\bull} If a slot has both an {bf :initform} and an {\bf :initarg}
slot option, and the initialization argument is defaulted using {\bf
:default-initargs}, and the {\bf :initform} form is neither used nor
evaluated.
--> last "and" should be "then"
<done>
∂15-Oct-87 1747 Moon@STONY-BROOK.SCRC.Symbolics.COM Corrections
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 15 Oct 87 17:47:27 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 256674; Thu 15-Oct-87 20:48:29 EDT
Date: Thu, 15 Oct 87 20:48 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Corrections
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
In-Reply-To: The message of 15 Oct 87 19:31 EDT from Dick Gabriel <RPG@SAIL.Stanford.EDU>
Message-ID: <19871016004824.7.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 15 Oct 87 1631 PDT
From: Dick Gabriel <RPG@SAIL.Stanford.EDU>
Ok, I've got the corrections in. Here are a few remaining questions
and comments:
\item{\bull} Otherwise, if the slot has an {\bf :initform} form, that form
is evaluated and the result is stored into the slot.
--> This is >only< done if the slot is uninitialized, according to what
we agreed on. A :before method could store into the slot, and in that
case the :initform would not override it, even though an initialization
argument would override it. Slightly strange, but it's what the group
converged on.
So, what's the best wording here? If we say ``otherwise, if the slot is
uninitialized and has....'' we are imprecise about where in the protocol
the :initform is taken into account. Do we want to say that if the slot is
uninitialized after the primary methods have a shot the :initform takes over?
Is it after all methods? Is it after initialize-instance?
No, it's done by the primary method for initialize-instance (the description, of
which this is a bulleted item, is all about what the default primary method
for initialize-instance does). After the primary method does its initarg
processing for a slot, if the slot is still uninitialized it does initform
processing for the slot. As it happens, the only way the slot can still be
uninitialized is if the initarg processing didn't do anything, so you could
put in an "otherwise"; I'm having trouble deciding whether I think that makes
the explanation less or more clear.
At one point I was ready to propose splitting these two actions of the
primary method for initialize-instance into two separate generic functions,
since they are not very closely connected really. However, I thought better
of it, especially since my main reason for wanting to split them up turned
out to be confused.
On initialization arguments being multiply defined, I expanded the
bullets in that neighborhood to look like this. The reason is that
I wanted it clear that slot-fillers could be multiply-defined, that
method-implemented's could be multiply-defined, and that there was
no barrier between the names of slot-fillers and method-implemented's:
\item{\bull} It is valid for a single initialization argument to
initialize more than one slot if the same initialization argument name
appears in more than one {\bf :initarg} slot option.
\item{\bull} It is valid for a single initialization argument to appear
in more than one initialization method lambda-list.
\item{\bull} It is valid for a given initialization argument name to
appear both in an {\bf :initarg} slot option and in the lambda-list
of an initialization method.
I like this.
``Should that be "uninitialized" or "unbound" slots or "slots that have no
values"?''
I want to avoid the term ``unbound slots'' to avoid having to discuss whether
there is such a thing as an unbound object and to avoid hinting at any
implementational questions.
OK, let's use "uninitialized" uniformly. Somewhere, probably best in
the description of slots around page 5, we'll need to define the term
"uninitialized slot." This could cross-reference slot-boundp, and needs
to make clear that reading an uninitialized slot is well-defined, rather
than just returning an unpredictable value (it calls the
slot-uninitialized generic function, if I correctly interpreted my notes
from the recent meeting).
<done>
∂30-Sep-87 2045 Moon@STONY-BROOK.SCRC.Symbolics.COM Amendments requiring additional writing
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 30 Sep 87 20:44:43 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 245796; Wed 30-Sep-87 23:45:30 EDT
Date: Wed, 30 Sep 87 23:45 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Amendments requiring additional writing
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
In-Reply-To: <870925214129.4.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870928-133654-19356@Xerox>,
<870928184306.6.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870929-085934-1876@Xerox>,
<870929-180832-1165@Xerox>,
<870930171107.8.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870930171528.9.MOON@EUPHRATES.SCRC.Symbolics.COM>,
The message of 30 Sep 87 18:21 EDT from Dick Gabriel <RPG@SAIL.STANFORD.EDU>,
<870930-152906-2790@Xerox>,
<870930201953.7.MOON@EUPHRATES.SCRC.Symbolics.COM>,
<870930-173045-3035@Xerox>,
<13275.560047705@hplabsz>
Message-ID: <870930234533.5.MOON@EUPHRATES.SCRC.Symbolics.COM>
Here is a replacement for pages 1-11 and 1-12, based on the referenced
mail and the latest CONCEP.TEX on SAIL. I offered to write this because
it incorporates an amended paragraph I sent out on 25 Sep, and because
Danny asked me to write it because he said he was too busy to do any
writing.
Note that we will probably want a separate section explaining how to
change the class of an object, using change-class. Note that
class-changed and update-instance-structure are currently incompatible
with respect to who evaluates the initforms; one of them has to be
changed. I didn't attempt to write anything for change-class. We
could always describe change-class only in the Function chapter, and
not have a Concept section for it.
I have not changed any local/shared/instance/class slot terminology.
We can change that later if we agree on the new terminology.
\beginSection{Redefining Classes}
When a {\bf defclass} form is evaluated and a class with the given
name already exists, the existing class is redefined. Redefining a
class modifies the existing class object to reflect the new class
definition; it does not create a new class object for the class. Any
method created by an {\bf :accessor} or {\bf :reader}
option specified by the old
{\bf defclass} form is removed from the corresponding generic
function unless that same method is specified by the new {\bf
defclass} form; any function specified by the {\bf :constructor}
option of the old {\bf defclass} form is removed from the
corresponding symbol function cell.
When the class $C$ is redefined, changes are propagated to instances
of it and to instances of any of its subclasses. The updating of an
instance whose class has been redefined (or any of whose superclasses
have been redefined) occurs at an implementation-dependent time, but
no later than the next time a slot of that instance is read or written.
Updating an instance does not change its identity as
defined by the {\bf eq} function. The updating process may change the
slots of that particular instance, but it does not create a new
instance. Whether updating an instance consumes storage is
implementation dependent.
If a class is redefined in such a way that the set of local slots
accessible in an instance of the class is changed or the order of slots
in storage is changed, the function {\bf update-instance-structure} is
called whenever an instance of the class is updated, to complete the
transformation from the old representation of the instance to the new
representation. Implementations may choose to invoke
{\bf update-instance-structure} under other circumstances as well.
Programmers can define methods for {\bf update-instance-structure} to
specify actions to be taken when an instance is updated. When
{\bf update-instance-structure} is called, the structure of the instance
has already been converted to conform to the new class definition,
and newly added slots are uninitialized.
Note that redefining a class may cause slots to be added or deleted.
When an instance is updated, new slots are initialized and the
values of deleted slots are discarded. Each local slot of the new
version of the class with no slot by the same name in the old version
of the class is initialized to the value of the corresponding {\bf
:initform} option of the new class or remains uninitialized if the new
version of the class does not specify or inherit the {\bf :initform} option for
that slot. This is the same as the initialization
done by {\bf make-instance} except that no initialization methods are
invoked and no {\bf make-instance} initialization arguments are
present. This initialization is performed by the default primary
method for {\bf update-instance-structure}.
\eject
If in the new version of the class there is a local slot of the same
name as any slot in the old version of the class, the value of that
slot is unchanged. This is true regardless of whether the old slot
was a local slot or a shared slot. This means that if the slot
has a value, the value returned by {\bf slot-value} after
class redefinition is {\bf eql} to the value returned by {\bf
slot-value} before class redefinition. Similarly, if the
slot was uninitialized, it remains uninitialized.
If in the new
version of the class there is a shared slot of the same name as any
shared slot in the old version of the class, the value of that slot
is unchanged. If in the new version of the class there is
a shared slot of the same name as any local slot in the old version of
the class, that shared slot is initialized to the value of the
corresponding {\bf :initform} option of the new class or remains
uninitialized if the new version of the class does not specify or
inherit the {\bf :initform} option for that slot. Shared slots
are updated at the moment of class redefinition and
are not affected by the updating of an instance nor by the
values of any local slots.
The \CLOS\ guarantees that {\bf defclass} can be used to change the
definition of an existing class that was previously defined by {\bf
defclass} as long as the {\bf :metaclass} option is not used in either
the old or the new definition. Whether {\bf defclass} is allowed to
change the metaclass and whether redefining a class causes existing
instances to be updated is up to the implementor of the particular
metaclass. ``The \CLOS\ Meta-Object Protocol'' will describe how to
control this.
\endSection%{Redefining Classes}
moon/su
Class-changed
Is it not the case that in the previous redefinition protocol, redefinition
invoke CHANGE-CLASS which invoked CLASS-CHANGED:
redefinition => CHANGE-CLASS => CLASS-CHANGED
and now we have
redefinition => UPDATE-INSTANCE-STRUCTURE
and presumably we will add
CHANGE-CLASS => UPDATE-INSTANCE-STRUCTURE
I suppose then that the processing of :initform's happens in
<redefinition> and in CHANGE-CLASS.
Is this all wet? Danny and Gregor appear to be out of the loop at the
moment.
-rpg-
∂15-Oct-87 2151 Bobrow.pa@Xerox.COM Re: Writing
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 15 Oct 87 21:51:46 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 15 OCT 87 21:52:21 PDT
Date: 15 Oct 87 21:52 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Writing
In-reply-to: Dick Gabriel <RPG@SAIL.Stanford.EDU>'s message of 10 Oct 87
14:04 PDT
To: RPG@SAIL.Stanford.EDU
cc: bobrow.pa@Xerox.COM
Message-ID: <871015-215221-3152@Xerox>
Dick,
If you don't have what you believe are final drafts of proposals I was
responsible for, please let me know. These include:
redefining classes (as sent out in final form by Moon)
class-changed which needs to be updated wrt initialization of slots
to correspond to redefining classes
no-applicable-method
slot-missing class
slot-uninitialized
next-method-p
I have been buried; Hope your head is geting above the shit.
danny
PS Will we see you here next week?
<done>
∂15-Oct-87 2224 Bobrow.pa@Xerox.COM [David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>:
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 15 Oct 87 22:24:31 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 15 OCT 87 22:25:10 PDT
Date: 15 Oct 87 22:25 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: [David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>:
Amendments requiring additional writing]
To: rpg@sail.stanford.edu
cc: Bobrow.pa@Xerox.COM
Message-ID: <871015-222510-3168@Xerox>
From Moon's message with slight edits, to reflect later comments:
Here is a replacement for pages 1-11 and 1-12, based on the referenced
mail and the latest CONCEP.TEX on SAIL.
We want a separate section explaining how to
change the class of an object, using change-class. Note that
class-changed and update-instance-structure are currently incompatible
with respect to who evaluates the initforms; one of them has to be
changed. This should be fixed.
I didn't attempt to write anything for change-class. We
could always describe change-class only in the Function chapter, and
not have a Concept section for it.
I have not changed any local/shared/instance/class slot terminology.
We can change that later if we agree on the new terminology.
\beginSection{Redefining Classes}
When a {\bf defclass} form is evaluated and a class with the given
name already exists, the existing class is redefined. Redefining a
class modifies the existing class object to reflect the new class
definition; it does not create a new class object for the class. Any
method created by an {\bf :accessor} or {\bf :reader}
option specified by the old
{\bf defclass} form is removed from the corresponding generic
function unless that same method is specified by the new {\bf
defclass} form.
When the class $C$ is redefined, changes are propagated to instances
of it and to instances of any of its subclasses. The updating of an
instance whose class has been redefined (or any of whose superclasses
have been redefined) occurs at an implementation-dependent time, but
no later than the next time a slot of that instance is read or written.
Updating an instance does not change its identity as
defined by the {\bf eq} function. The updating process may change the
slots of that particular instance, but it does not create a new
instance. Whether updating an instance consumes storage is
implementation dependent.
If a class is redefined in such a way that the set of local slots
accessible in an instance of the class is changed or the order of slots
in storage is changed, the function {\bf update-instance-structure} is
called whenever an instance of the class is updated, to complete the
transformation from the old representation of the instance to the new
representation. Implementations may choose to invoke
{\bf update-instance-structure} under other circumstances as well.
Programmers can define methods for {\bf update-instance-structure} to
specify actions to be taken when an instance is updated. When
{\bf update-instance-structure} is called, the structure of the instance
has already been converted to conform to the new class definition,
and newly added slots are uninitialized.
Note that redefining a class may cause slots to be added or deleted.
When an instance is updated, new slots are initialized and the
values of deleted slots are discarded. Each local slot of the new
version of the class with no slot by the same name in the old version
of the class is initialized to the value of the corresponding {\bf
:initform} option of the new class or remains uninitialized if the new
version of the class does not specify or inherit the {\bf :initform}
option for
that slot. This is the same as the initialization
done by {\bf make-instance} except that no initialization methods are
invoked and no {\bf make-instance} initialization arguments are
present. This initialization is performed by the default primary
method for {\bf update-instance-structure}.
\eject
If in the new version of the class there is a local slot of the same
name as any slot in the old version of the class, the value of that
slot is unchanged. This is true regardless of whether the old slot
was a local slot or a shared slot. This means that if the slot
has a value, the value returned by {\bf slot-value} after
class redefinition is {\bf eql} to the value returned by {\bf
slot-value} before class redefinition. Similarly, if the
slot was uninitialized, it remains uninitialized.
If in the new
version of the class there is a shared slot of the same name as any
shared slot in the old version of the class, the value of that slot
is unchanged. If in the new version of the class there is
a shared slot of the same name as any local slot in the old version of
the class, that shared slot is initialized to the value of the
corresponding {\bf :initform} option of the new class or remains
uninitialized if the new version of the class does not specify or
inherit the {\bf :initform} option for that slot. Shared slots
are updated at the moment of class redefinition and
are not affected by the updating of an instance nor by the
values of any local slots.
The \CLOS\ guarantees that the user can change the definition of an
existing class that is a standard-class, and cause its instances to be
updated. Whether redefining a class that is not a standard-class causes
existing instances to be updated is up to the implementor of the
particular metaclass. ``The \CLOS\ Meta-Object Protocol'' will describe
how to control this.
\endSection%{Redefining Classes}
∂16-Oct-87 0833 skeene@STONY-BROOK.SCRC.Symbolics.COM don't forget the hardcopy
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 16 Oct 87 08:32:56 PDT
Received: from JUNCO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 257056; Fri 16-Oct-87 11:33:50 EDT
Date: Fri, 16 Oct 87 11:33 EDT
From: Sonya E. Keene <skeene@STONY-BROOK.SCRC.Symbolics.COM>
Subject: don't forget the hardcopy
To: RPG@SAIL.Stanford.EDU, lgd@SAIL.Stanford.EDU
Message-ID: <19871016153329.9.SKEENE@JUNCO.SCRC.Symbolics.COM>
I also had some changes to the spec that were noted in a hardcopy passed
out in Sept. They didn't get duplicated in the mail because they were
all agreed on.
Also, let me know if you'd like me to help out in the last push to
finalize the document.
<done>
∂16-Oct-87 0924 Moon@STONY-BROOK.SCRC.Symbolics.COM Redefining classes etc
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 16 Oct 87 09:24:38 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 257090; Fri 16-Oct-87 12:19:43 EDT
Date: Fri, 16 Oct 87 12:19 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Redefining classes etc
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
In-Reply-To: The message of 15 Oct 87 23:58 EDT from Dick Gabriel <RPG@SAIL.Stanford.EDU>
Message-ID: <19871016161935.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 15 Oct 87 2058 PDT
From: Dick Gabriel <RPG@SAIL.Stanford.EDU>
Who was writing this? Danny?
2 or 3 weeks back Danny phoned me and asked me to write (or update I
guess) his writeup on this, so I did and mailed it out. I don't
remember anything happening after that; I haven't been keeping
careful track of the class redefinition discussion.
I found that message, so I have just resent it to you under
separate cover. According to my mail records, often not reliable,
it was not answered.
What's the story on constructors - in or out?
Nobody in Palo Alto except MLY likes them, and he only sends his
messages to me personally. Okay, he's not in Palo Alto any more, but I
think he was when he sent the first message. Well, actually, he was in
Menlo Park, so I guess that's why he likes constructors.
I haven't heard from you, maybe you don't have an opinion. The people
well outside Palo Alto like them. I think constructors are in the
pending issues category for now. With Gregor out of the picture, it's
hard to continue the discussion, since he is the most articulate
opponent of putting them in.
∂24-Sep-87 0915 Bobrow.pa@Xerox.COM Redefining Classes
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 24 Sep 87 09:15:37 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 24 SEP 87 09:12:59 PDT
Date: 24 Sep 87 09:12 PDT
From: Bobrow.pa@Xerox.COM
Subject: Redefining Classes
To: Common-Lisp-Object-System@Sail.stanford.edu
Message-ID: <870924-091259-15052@Xerox>
Redefining Classes
When a defclass form is evaluated and a class with the given name
already exists, the existing class is redefined. This may also cause
some of the subclasses of the redefined class to also be redefined.
Classes my also be redefined using the metaobject protocol -- see the
functions add-named-class and update-class.
For instances of standard-class, redefining a class modifies the
existing class object to reflect the new class definition; it does not
create a new class object for the class. Any method created by an
:accessor, :reader, specified by the old defclass form is removed from
the corresponding generic function unless that same method is specified
by the new defclass form.
If the redefinition of a class causes the structure of its instances to
be different, and the class has instances, then the generic function
make-instances-obsolete is called. The function make-instances-obsolete
takes as its one argument the class to be redefined. This invocation
captures the state of the class before redefinition, and marks all
existing instances of the class as obsolete. Such instances will be
updated to the new structure determined by the class redefinition. This
updating will be done in such a way that users will never see an
instance with the obsolete structure. THIS IS ONLY GUARANTEED TO BE
SUPPORTED FOR CLASSES THAT ARE INSTANCES OF STANDARD CLASS.
make-instances-obsolete class (generic-function)
Obsolete instance updating is done in two stages:
1) The system creates a property list that captures the slot names and
values of all the slots of the obsolete instance. It then transforms
the structure of the instance, so that it conforms to the current class
definition. All the slots of this transformed instance are
uninitialized. This first stage cannot be seen by user programs.
2) The generic function update-instance-structure is called. Its
arguments are the transformed instance, and the property list of
slot-names and values corresponding to the state of the obsolete
instance. Its contract is to do appropriate updating of the instance,
using the values from the obsolete slots.
Because update-instance-structure is user code, its operation can be seen
by the user; but the model that CLOS supports is that as far as the user
can tell, all the existing instances of a class are updated as soon as
the class redefinition happens. This implies that the user must define
a method for update-instance-structure before redefining a class.
Implementations are free to delay the conversion of existing instances
(for example, to method call or slot access time), but users should
never be able to see the untransformed instance.
update-instance-structure instance property-list (generic-function)
The method on update-instance-structure defined on the class Object does
the following:
1) for each instance slot in current definition of class, if its
slot-name appears in the property list, the value corresponding to the
slot-name in the property-list is installed in the instance slot. Class
slots in the current definition of class are assumed to have their
correct value, and are not changed.
2) For any slot in the instance which is still unbound, and for which
there is an :initform expression in the current class definition, the
initform is evaluated and the value installed in that slot.
The generic function update-instance-structure is not intended to be
called by programmers. Programmers are expected to write methods for
it. The function update-instance-structure is called by the system to
update an obsolete instance.
∂30-Sep-87 0936 Moon@STONY-BROOK.SCRC.Symbolics.COM Constructors
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 30 Sep 87 09:36:17 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 244977; Wed 30-Sep-87 12:37:07 EDT
Date: Wed, 30 Sep 87 12:37 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Constructors
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Message-ID: <870930123711.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
This is a proposal to add constructors back into CLOS, now that the basic
object creation protocol has been agreed upon.
Note that this proposal has been greatly simplified compared to what was being
discussed last spring. In response to several cogent objections that were
raised, a number of problematic features have been removed and constructors
have been made easier to understand and to use. While these proposed
constructors are somewhat different from the constructors whose usefulness has
been verified by their use in New Flavors, a survey of 242 constructors used
in a variety of Flavors-based programs showed that these CLOS constructors
should meet the needs of those programs, which I am assuming to be in some
sense typical. The only real change to those programs would be the
requirement that any slot to be filled by a constructor must have an initarg,
and I don't think that presents any difficulty.
Survey of 242 constructors for 237 different flavors:
83 with MAKE-INSTANCE-style arguments.
Of the remaining 159 constructors:
140 with required arguments only, 8 also with optional or rest,
11 with keyword arguments. 0 with &aux parameters.
15 take no arguments, 102 only fill slots, 3 also specify area,
39 take initargs.
142 fill slots, of which 0 use the initarg rather than the slot name,
and 85 fill slots that don't have initargs. 103 fill inherited slots.
WHY HAVE CONSTRUCTORS?
(1) A cleaner interface for the caller
It's often appropriate to have a more abstract interface than the one provided
by MAKE-INSTANCE. Providing a constructor as the documented inter-module
interface for making a particular kind of object encourages users of the
interface to think in more abstract, conceptual terms. Using a constructor
also allows more aspects of the implementation to be changed without changing
the interface: the class name and initarg names could be changed, or the data
representation could be changed to a DEFSTRUCT representation or a
standard-type, without changing the interface. The constructor could even be
replaced by an interface function that does some complex computations to
decide what type of object to create, or to decide whether to return an
existing object or create a new one.
These needs could be met simply by defining constructor functions with DEFUN
and advertising them. Some reasons to have a :CONSTRUCTOR option in
DEFCLASS are
- to make it easier and more convenient for users to create constructors
- to be culturally consistent with DEFSTRUCT
- :CONSTRUCTOR is a convenient abbreviation for something you could do yourself
in a more long-winded way, just like :ACCESSOR
Other reasons appear below.
(2) Coordination with class redefinition
As the bridge between an external interface and the internal structure of a
class, a constructor function contains certain information about the class,
such as what are its initargs and their default values. When a class is
redefined, any constructors for the class and its subclasses should be updated
if necessary to keep them consistent with the class. Making this updating
automatic is a convenience for programmers, so they don't have to remember to
do it by hand. One way to make the updating automatic would be to add a new
feature to the programming environment by which a linkage could be established
between a function and a class so that redefining the class makes some edits
to the source of the function and then recompiles it. A much simpler way is
to make the constructor syntactically part of the DEFCLASS, so it naturally
gets updated at the same time as the rest of the DEFCLASS. This is another
way in which constructors are analogous to accessors.
(3) More efficient than MAKE-INSTANCE
MAKE-INSTANCE must operate by interpreting data structures that describe the
class, while constructors can be compiled, since they know the exact class
that they are constructing, and since they can be automatically recompiled if
the class or any of its superclasses changes. Initialization methods can be
completely inlined into a constructor, where MAKE-INSTANCE has to go through a
generic function dispatch. Constructors can take positional arguments, which
are more efficient in most implementations, while MAKE-INSTANCE requires
keyword arguments.
Gregor has argued that calls to MAKE-INSTANCE with a constant first argument
can be equally optimized, since the exact class being constructed is known.
While this is true in theory, it seems that either a complicated mechanism
would be needed to make sure that the function was recompiled when the class
was redefined in a way that invalidated the inline code, or else there would
have to be user-visible declarations to control the tradeoff between
performance and robustness in the face of class redefinition. Alternatively,
calls to MAKE-INSTANCE with a constant first argument could be turned into
calls to a constructor function that was created behind the scenes. Then if
the class was redefined, only the constructor function would have to be
recompiled. In either case, if we are going to have this type of mechanism, I
would much rather make it explicitly visible as a :CONSTRUCTOR option than
have it operating behind the scenes in some vaguely defined way.
WHY GET RID OF CONSTRUCTORS?
(1) Simplicity
If we have both constructors and MAKE-INSTANCE, then we have two ways to
do the same thing.
[But CLOS very often provides both a primitive mechanism and a convenient
abbreviation for a common case of using that mechanism.]
The rules for mapping constructor parameter names into slots and initargs are
complicated and confusing.
[Very true. In this proposal they have been enormously simplified.]
(2) Avoid hiding mechanisms
Constructors contain a hidden performance optimization, in that there is
more inlining in their bodies than can be achieved through documented
mechanisms elsewhere.
[I argued above that this is preferable to the inherent complexity of
making that mechanism generally available. Of course there is nothing
to stop us from documenting it if that's what we really want.
Also, exactly the same thing could be said about :ACCESSOR, at least
in the Symbolics implementation.]
(3) Not more efficient than MAKE-INSTANCE
(see discussion above)
SYNTAX
The DEFCLASS option (:CONSTRUCTOR -symbol-) creates a function named -symbol-
that takes the initargs of this class as keyword arguments and returns an
instance of this class. Thus a call to -symbol- looks just like a call to
MAKE-INSTANCE with the first argument omitted.
The DEFCLASS option (:CONSTRUCTOR -symbol- -constructor-lambda-list-) creates
a function named -symbol- whose lambda-list is -constructor-lambda-list-. The
function returns an instance of this class, initialized according to the
parameters in -constructor-lambda-list-. Each parameter supplies the value of
one initarg, determined by the following rules:
- If a parameter variable name is EQ to an initarg name, the parameter
supplies the value of that initarg.
- If a parameter variable name is not EQ to any initarg name, but the symbol
in the keyword package with the same name as the parameter variable
name is EQ to an initarg name, the parameter supplies the value of that
initarg.
- If neither rule succeeds, signal an error.
The second rule exists because initarg names are often keyword symbols, which
are not valid as variable names.
-constructor-lambda-list- allows all of the standard lambda-list features that
DEFUN allows. The only difference is that if no initform is specified for an
&optional, &key, or &aux parameter, instead of just defaulting to NIL, the
parameter defaults in a special way, as in DEFSTRUCT constructors. An
&optional or &key parameter with no initform defaults to the corresponding
initarg's default-initarg form, or if there is none defaults to NIL but is
not passed to initialization methods if unsupplied.
An &aux parameter with no initform defaults to NIL but always behaves as if
unsupplied: the corresponding initarg is not passed to initialization methods
and if there is a default-initarg form, it is never evaluated. (This feature
comes from DEFSTRUCT. Since &aux was never used in constructors in the
Flavors programs I surveyed, I wouldn't propose it if DEFSTRUCT hadn't already
introduced it into Common Lisp.)
The :CONSTRUCTOR option can appear more than once in a DEFCLASS form.
PROCEDURAL DEFINITION OF CONSTRUCTORS
After receiving and defaulting its arguments, a constructor forms an initarg
list from its parameters and calls MAKE-INSTANCE with the appropriate class
object as the first argument and the initarg list as the remaining arguments.
The actual code compiled for a constructor can be optimized in
implementation-dependent ways, as long as it has the same effect as above.
For example, instead of calling MAKE-INSTANCE, the constructor can inline the
body of MAKE-INSTANCE and the bodies of some or all of the methods that
MAKE-INSTANCE calls. This implies that the initarg list might not be fully
materialized, parameter values might really be stored directly into slots, and
keyword argument processing might be completely eliminated. Any optimization
of this type is valid as long as the same effect as calling MAKE-INSTANCE is
achieved and the compiled code is updated when the class or a superclass is
redefined or a relevant method is added or removed.
WHEN ARE CONSTRUCTORS DEFINED AND REDEFINED?
A constructor for a class C cannot be accurately defined until each of
C and its superclasses is defined and all applicable INITIALIZE-INSTANCE
and ALLOCATE-INSTANCE methods have been defined. Until then, the set
of initargs and default-initarg forms is not known.
The macro-expansion of DEFCLASS includes a DEFUN for each constructor
based on the information available at the time DEFCLASS is expanded. If any
superclass is not yet defined, this constructor is a dummy that simply signals
an error. At any later time when C is redefined, a superclass of C is defined
or redefined, or a relevant method is added or removed, CLOS considers each
constructor for C and if necessary recompiles it. If a class is redefined and
a :CONSTRUCTOR is removed, FMAKUNBOUND is applied to the former constructor's
name. Thus a constructor is always up to date with the latest information
about its class.
Note that a user might extract the constructor function from the function
definition of its name, redefine the class (thus redefining the constructor),
and then call the out of date constructor function. Implementations should be
robust in the face of this, either signalling an error when an out of date
constructor function is called, automatically calling the latest version of
the constructor function, or making an instance of the class as it used to be
defined and then updating it as if the class had been redefined after the
instance was made. This follows from the principle that optimization of a
constructor function should not affect its semantics.
This is better than the way Flavors does it, which involves only creating
constructors in COMPILE-FLAVOR-METHODS.
PRIMITIVES FOR MAKING CONSTRUCTORS
At the meta-object level, there will be primitive functions for turning a
constructor lambda-list into a function by filling in parameter defaults and
computing the function body, verifying that a constructor is still valid, and
establishing and removing the linkage between a class and a constructor. A
default method for some function that gets called when things are redefined
will call these functions, to keep the constructors up to date.
Very roughly, these will be:
MAKE-CONSTRUCTOR class name &optional constructor-option-second-argument
-> lambda-expression form
To install the constructor function, evaluate
(PROGN (SETF (SYMBOL-FUNCTION 'name) #'lambda-expression)
form
(LINK-CONSTRUCTOR 'class 'name T)
'name)
VERIFY-CONSTRUCTOR class name &optional constructor-option-second-argument
-> Boolean
LINK-CONSTRUCTOR class name on-or-off
We could also expose the next level down, which defines how class and
constructor-option-second-argument are turned into information that is
compared by VERIFY-CONSTRUCTOR to see whether the constructor needs to be
regenerated, and defines how the form returned by MAKE-CONSTRUCTOR as its
second value records this information. (This form is a bit of a crock. In
the Symbolics system, it isn't necessary, because all information is in the
lambda-expression and in the compiled-function object compiled from it.
However, I'm assuming that some implementations cannot do this, and therefore
provision is needed to associate this information with the name of the
constructor rather than with the actual function object. If we can get rid of
this, great. Of course LINK-CONSTRUCTOR still needs the name so class
redefinition knows where to store the updated constructor.)
∂24-Sep-87 0915 Bobrow.pa@Xerox.COM Redefining Classes
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 24 Sep 87 09:15:37 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 24 SEP 87 09:12:59 PDT
Date: 24 Sep 87 09:12 PDT
From: Bobrow.pa@Xerox.COM
Subject: Redefining Classes
To: Common-Lisp-Object-System@Sail.stanford.edu
Message-ID: <870924-091259-15052@Xerox>
Redefining Classes
When a defclass form is evaluated and a class with the given name
already exists, the existing class is redefined. This may also cause
some of the subclasses of the redefined class to also be redefined.
Classes my also be redefined using the metaobject protocol -- see the
functions add-named-class and update-class.
For instances of standard-class, redefining a class modifies the
existing class object to reflect the new class definition; it does not
create a new class object for the class. Any method created by an
:accessor, :reader, specified by the old defclass form is removed from
the corresponding generic function unless that same method is specified
by the new defclass form.
If the redefinition of a class causes the structure of its instances to
be different, and the class has instances, then the generic function
make-instances-obsolete is called. The function make-instances-obsolete
takes as its one argument the class to be redefined. This invocation
captures the state of the class before redefinition, and marks all
existing instances of the class as obsolete. Such instances will be
updated to the new structure determined by the class redefinition. This
updating will be done in such a way that users will never see an
instance with the obsolete structure. THIS IS ONLY GUARANTEED TO BE
SUPPORTED FOR CLASSES THAT ARE INSTANCES OF STANDARD CLASS.
make-instances-obsolete class (generic-function)
Obsolete instance updating is done in two stages:
1) The system creates a property list that captures the slot names and
values of all the slots of the obsolete instance. It then transforms
the structure of the instance, so that it conforms to the current class
definition. All the slots of this transformed instance are
uninitialized. This first stage cannot be seen by user programs.
2) The generic function update-obsolete-instance is called. Its
arguments are the transformed instance, and the property list of
slot-names and values corresponding to the state of the obsolete
instance. Its contract is to do appropriate updating of the instance,
using the values from the obsolete slots.
Because update-obsolete-instance is user code, its operation can be seen
by the user; but the model that CLOS supports is that as far as the user
can tell, all the existing instances of a class are updated as soon as
the class redefinition happens. This implies that the user must define
a method for update-obsolete-instance before redefining a class.
Implementations are free to delay the conversion of existing instances
(for example, to method call or slot access time), but users should
never be able to see the untransformed instance.
update-obsolete-instance instance property-list (generic-function)
The method on update-obsolete-instance defined on the class Object does
the following:
1) for each instance slot in current definition of class, if its
slot-name appears in the property list, the value corresponding to the
slot-name in the property-list is installed in the instance slot. Class
slots in the current definition of class are assumed to have their
correct value, and are not changed.
2) For any slot in the instance which is still unbound, and for which
there is an :initform expression in the current class definition, the
initform is evaluated and the value installed in that slot.
The generic function update-obsolete-instance is not intended to be
called by programmers. Programmers are expected to write methods for
it. The function update-obsolete-instance is called by the system to
update an obsolete instance.
∂20-Oct-87 1353 Moon@STONY-BROOK.SCRC.Symbolics.COM documentation documentation
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 20 Oct 87 13:53:22 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 259416; Tue 20-Oct-87 16:54:18 EDT
Date: Tue, 20 Oct 87 16:54 EDT
From: SKeene@STONY-BROOK.SCRC.Symbolics.COM, Moon@STONY-BROOK.SCRC.Symbolics.COM
Sender: Moon@STONY-BROOK.SCRC.Symbolics.COM
Subject: documentation documentation
To: rpg@sail.stanford.edu
Message-ID: <19871020205419.6.MOON@EUPHRATES.SCRC.Symbolics.COM>
\begincom{documentation}\ftype{Generic Function}
\label Purpose:
The Common Lisp function {\bf documentation} is replaced by a generic
function. The generic function {\bf documentation} returns the
documentation string associated with the given object if it is
available; otherwise it returns {\bf nil}.
\label Syntax:
\Defgen documentation {x {\opt} doc-type}
\label Arguments:
The first argument is either a symbol, a list such as {\tt (setf {\it
symbol\/})}, a method object, a class object, or a generic function
object.
If the first argument is a method object, a class object, or a generic
function object, the second argument must not be supplied. {\bf
documentation} returns the documentation string of that object.
If the first argument is a symbol or a list, the second argument must be
supplied. The {\it doc-type\/} argument is a symbol. It can be one
of the following types: {\bf variable}, {\bf function}, {\bf structure},
{\bf type}, {\bf setf}, and {\bf method-combination}. The generic
function {\bf documentation} returns the documentation string of the
given type.
{\tt (documentation {\it symbol\/} 'type)} returns the documentation
string of the class object named by the symbol, if there is such a
class. Otherwise it returns the documentation string of the type
specifier named by the symbol.
{\tt (documentation {\it symbol-or-list\/} 'function)} returns the
documentation string of the function, generic function, special form, or
macro named by the symbol or list.
{\tt (documentation {\it symbol\/} 'method-combination)} returns the
documentation string of the method combination type named by the
symbol.
{\tt (documentation {\it symbol\/} 'setf)} returns the documentation
string of the {\bf defsetf} or {\bf define-setf-method} associated with
the symbol.
\label Values:
The documentation string associated with the given object is returned
unless none is available, in which case {\bf documentation} returns
{\bf nil}.
\label Remarks:
The macro {\bf setf} can be used with {\bf documentation} to update the
documentation.
\endcom
∂20-Oct-87 1342 Moon@STONY-BROOK.SCRC.Symbolics.COM Finalize-inheritance
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 20 Oct 87 13:42:43 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 259407; Tue 20-Oct-87 16:43:38 EDT
Date: Tue, 20 Oct 87 16:43 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Finalize-inheritance
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
cc: skeene@STONY-BROOK.SCRC.Symbolics.COM, Moon@STONY-BROOK.SCRC.Symbolics.COM
In-Reply-To: The message of 20 Oct 87 16:03 EDT from Dick Gabriel <RPG@SAIL.Stanford.EDU>
Message-ID: <19871020204335.5.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 20 Oct 87 1303 PDT
From: Dick Gabriel <RPG@SAIL.Stanford.EDU>
Could one of you figure out a chapter-2-like set of
documentation for this guy? Thanks. It is slated for
chapter 3 at the moment.
I think it belongs in chapter 3. What sort of documentation
do you want? I would think just a sentence mentioning its
existence as part of the optimization mechanism behind the
scenes in make-instance would be enough.
moon/su
Finalize-inheritance
Well, the current description, which is a nearly a direct quote from
someone's writeup, states:
``The generic function FINALIZE-INHERITANCE is called at least once
before a class is instantiated and is called again whenever anything
relevant changes.
``The system-supplied methods for FINALIZE-INHERITANCE conspire
with methods for CHECK-INITARGS and other functions to make
MAKE-INSTANCE faster.''
I'm not especially eager to have this explanation linger in the document.
-rpg-
∂19-Oct-87 0905 Moon@STONY-BROOK.SCRC.Symbolics.COM Class-changed
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 19 Oct 87 09:05:33 PDT
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 258305; Mon 19-Oct-87 11:34:32 EDT
Date: Mon, 19 Oct 87 11:34 EDT
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Class-changed
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
In-Reply-To: The message of 17 Oct 87 15:52 EDT from Dick Gabriel <RPG@SAIL.Stanford.EDU>
Message-ID: <19871019153433.4.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 17 Oct 87 1252 PDT
From: Dick Gabriel <RPG@SAIL.Stanford.EDU>
Is it not the case that in the previous redefinition protocol, redefinition
invoke CHANGE-CLASS which invoked CLASS-CHANGED:
redefinition => CHANGE-CLASS => CLASS-CHANGED
and now we have
redefinition => UPDATE-INSTANCE-STRUCTURE
OK so far.
and presumably we will add
CHANGE-CLASS => UPDATE-INSTANCE-STRUCTURE
No! The big point was to separate the class-redefinition protocol
from the change-class-of-instance protocol. CHANGE-CLASS will continue
to call CLASS-CHANGED. As far as I know the the change-class-of-instance
protocol remains unchanged, except that its writeup needs to be purged
of references to the class-redefinition protocol.
I suppose then that the processing of :initform's happens in
<redefinition> and in CHANGE-CLASS.
As far as I can decode from the various documents, in the
change-class-of-instance protocol :INITFORMs are evaluated
before CLASS-CHANGED is called (thus in CHANGE-CLASS or something
it calls). In the class-redefinition protocol, the out of date
document I have says the default method for UPDATE-INSTANCE-STRUCTURE
does the :INITFORMs, but I think we might have changed that to be
consistent with the change-class-of-instance protocol and do all the
slot initialization before calling the user-specializable function.
This would also make local slots more consistent with shared slots,
which get updated long before UPDATE-INSTANCE-STRUCTURE is called.
I can't remember. I could check the mail archive for October, I
suppose.
Is this all wet? Danny and Gregor appear to be out of the loop at the
moment.
They haven't been pulling their weight lately, have they?
∂19-Oct-87 0917 Bobrow.pa@Xerox.COM Re: Redefinition
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 19 Oct 87 09:17:44 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 19 OCT 87 09:17:20 PDT
Date: 19 Oct 87 09:17 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Redefinition
In-reply-to: Dick Gabriel <RPG@SAIL.Stanford.EDU>'s message of 17 Oct 87
14:48 PDT
To: RPG@SAIL.Stanford.EDU
cc: bobrow.pa@Xerox.COM
Message-ID: <871019-091720-6081@Xerox>
change-class is the same as it was, but is completely independent of
class redefinition. change-class allows a user to request the change of
an instance from being an instance of one currently defined class to
another. change-class takes care
1) Transforming the instance structure to the newly specified
structure
2) Moving over the values of slots (including unbound) that have
common names
3) calling class-changed
To be consistent with update-from-obsolete-instance (or is it called
update-instance-structure now), the default method on class-changed
should evaluate the initforms of any slots that are in the new instance
structure, but not the old.
Examples:
(defmethod class-changed ((p1 x-y-point ) (p2 rho-theta-point))
(setf (slot-value p2 'rho) (rho p1)
(slot-value p2 'theta) (theta p1)))
(defmethod class-changed ((s square)(r rectangle))
(setf (slot-value r 'width) (slot-value s 'size)
(slot-value r 'height) (slot-value s 'size)))
(defclass box ()
(width height))
(defclass black-box (box)
((color :initform 'black)))
Then
(change-class (make-instance 'box) 'black-box)
would fill in the color slot.
∂19-Oct-87 0941 Bobrow.pa@Xerox.COM Re: Redefinition
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 19 Oct 87 09:41:16 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 19 OCT 87 09:40:50 PDT
Date: 19 Oct 87 09:40 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Redefinition
In-reply-to: Dick Gabriel <RPG@SAIL.Stanford.EDU>'s message of 17 Oct 87
14:48 PDT
To: RPG@SAIL.Stanford.EDU
cc: bobrow.pa@Xerox.COM
Message-ID: <871019-094050-6137@Xerox>
And, is make-instances-obsolete for real? What does it do? When
is it called? Does it invoke change-class or
update-instance-structure?
make-instances-obsolete is for real. It is called when a class is
redefined in such a way as to make the instances obsolete. It is called
atomically with the class redefinition. It can also be called directly
by the user. It does not invoke change-class. It has the effect as if
all the current instances of the class were made obsolete. At an
implementation dependent time, the instance structure will be updated to
that specified by the current class defintion. This is done in two
stages. The first stage is completely invisible to the user.
Stage 1 transforms the instance structure to the currently specified
instance structure, and transfers all values of common slots have to the
new instance structure.
Stage 2, takes place after the Stage 1 and no later than the first
time slot-value or (setf slot-value) is called on the instance. It is
implemented by the method update-instance-structure.
update-instance-structure takesfour arguments:
the instance
a list of the names of all added slots
a list of the names of all deleted slots
a property list giving the values of all deleted, bound slots
See writeup as sent by Moon. The call to update-instance-structure is
completed before the slot-value or (setf slot-value) is processed.
Examples:
(defclass box ()
((width :initform 10)
(height :initform 10)))
(setq foo (make-instance 'box))
(defclass box ()
((width :initform 10)
(height :initform 10)
(color :initform 0)))
(slot-value foo 'color) ==> 0
(setf (slot-value foo 'color) 13)
(defmethod update-instance-structure
((b box) added deleted deleted-bound)
(call-next-method) ;; in case this is very old instance
(setf (slot-value b 'erase-color) (- 31 (slot-value b 'color))))
(defclass box ()
((width :initform 10)
(height :initform 10)
(color :initform 0)
(erase-color :initform 31)))
(slot-value foo 'erase-color) ==> 18
∂19-Oct-87 0946 Bobrow.pa@Xerox.COM Re: Redefinition
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 19 Oct 87 09:46:06 PDT
Received: from Cabernet.ms by ArpaGateway.ms ; 19 OCT 87 09:46:48 PDT
Date: 19 Oct 87 09:46 PDT
Sender: Bobrow.pa@Xerox.COM
From: Danny Bobrow <Bobrow.pa@Xerox.COM>
Subject: Re: Redefinition
In-reply-to: Dick Gabriel <RPG@SAIL.Stanford.EDU>'s message of 17 Oct 87
14:48 PDT
To: RPG@SAIL.Stanford.EDU
cc: bobrow.pa@Xerox.COM
Message-ID: <871019-094648-6156@Xerox>
An example of when a user might call make-instances-obsolete
(defclass bordered-box (box)
((border :initform 1)))
;; make some instance of bordered-box
;; Now decide that widths, which used to not include their border
;; should include the border
(defmethod update-instance-structure
((b bordered-box) added deleted deleted-bound)
(setf (slot-value b 'width)
(+ (slot-value b 'width)
(* 2 (slot-value b 'border)))))
(make-instances-obsolete (symbol-class 'bordered-box))
Now they will all be updated.
∂23-Oct-87 1457 Gregor.pa@Xerox.COM Clear Versus Black Box
Received: from XEROX.COM by SAIL.STANFORD.EDU with TCP; 23 Oct 87 14:57:26 PDT
Received: from Semillon.ms by ArpaGateway.ms ; 23 OCT 87 14:54:02 PDT
Date: Fri, 23 Oct 87 14:53 PDT
From: Gregor.pa@Xerox.COM
Subject: Clear Versus Black Box
To: Dick Gabriel <RPG@SAIL.Stanford.EDU>
In-Reply-To: The message of 22 Oct 87 13:38 PDT from Dick Gabriel
<RPG@SAIL.Stanford.EDU>
Message-ID: <871023145348.3.GREGOR@SPIFF.isl.parc.xerox.com>
Line-fold: no
Hmm...
(defun foo (x)
(flet ((f1 (r) ..)
(f2 (r) ..))
(cond ((mumble x) #'f1)
((frotz x) #'f2)
(t nil))))
(defmethod bar ((x integer))
#'call-next-method) ;FLAG (all hail to the chief
; down goes the dow)
(defmethod bar ((x number))
())
Now in terms of these two examples, who is the author and who is the
user.
Specifically, I believe this example shows that unless you believe the
person writing the flagged code is not allowed to treat the behavior of
call-next-method as a contract they can rely on, then from all the
relevant places, the relevant things are in fact not seen as a black
box.
Anyways, enough of this for now.
-------
gregor.pa@xerox/su
Example
Here is a precise statement of the clarity of the box. Suppose I
define a generic function in the sense that I specify its protocol.
That is, I publish a specification that states that the action of the
generic function is <action> and that users of this generic function
can define methods for it if they satisfy some constraints - usually this
is some semantic constraint. I might also publish that in primary
methods a CALL-NEXT-METHOD might accomplish some behavior. In any event, the
point is that I literally publish this specification on paper and send you
object code which you can modify by defining methods.
Now, I go ahead and define some complicated method combination, knowing that
I've told you everything you need to know to use my generic function, including
what to expect from CALL-NEXT-METHOD. I am the author of the generic function.
You, the user, decide to break the contract by writing a method that returns
a closure. I have not anticipated this, and, in fact, maybe I assume that
once a generic function invocation has ended, no part of it can be resumed.
Do I publish this funny-sounding proviso? Do I make up a method combination
type that has an UNWIND-PROTECT in it?
Sure, I can do all these things, but with dynamic extent on CALL-NEXT-METHOD,
I have less to worry about because you have fewer ways to break my abstraction.
This isn't a compelling argument, but it clarifies what I mean by the
author and the user.
-rpg-
As of: Oct 26, 15:52
Moon and Danny say:
class-changed and update-instance-structure - primary method on
standard-object does initialization.
standard-object is a subclass of T. See message by danny and
gregor about this and print-object. Superclass of anything that
is an instance of standard-class.
Moon to write up built-in.
constructors out.
lexical scope, indefinite extent
:lambda-list initarg for make-instance of 'method.
∂26-Oct-87 1942 Moon@STONY-BROOK.SCRC.Symbolics.COM Constructors
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 26 Oct 87 19:42:01 PST
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 264275; Mon 26-Oct-87 22:43:09 EST
Date: Mon, 26 Oct 87 22:42 EST
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Constructors
To: Dick Gabriel <RPG@SAIL.STANFORD.EDU>
In-Reply-To: The message of 26 Oct 87 14:51 EST from Dick Gabriel <RPG@SAIL.Stanford.EDU>
Message-ID: <19871027034256.2.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 26 Oct 87 1151 PST
From: Dick Gabriel <RPG@SAIL.Stanford.EDU>
What about constructors? Danny claims we all agreed to
postpone on them until we decide. I think now is the time to
decide.
I've been putting them off because of the pressure to finish
all the other stuff. I spoke to Danny on the phone for a while
today, and tentatively came to the conclusion that if we spend
some face-to-face time on constructors in Colorado we might reach
agreement. Of course it would be better to decide before the
X3J13 mailing, but I'm not sure I can find the time.
∂26-Oct-87 2146 COMMON-LISP-OBJECT-SYSTEM-mailer Some open issues
Received: from SCRC-STONY-BROOK.ARPA by SAIL.STANFORD.EDU with TCP; 26 Oct 87 21:45:59 PST
Received: from EUPHRATES.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 264295; Tue 27-Oct-87 00:04:48 EST
Date: Tue, 27 Oct 87 00:04 EST
From: David A. Moon <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Subject: Some open issues
To: Common-Lisp-Object-System@SAIL.STANFORD.EDU
Message-ID: <19871027050430.3.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: 26 Oct 87 1130 PST
From: Dick Gabriel <RPG@SAIL.Stanford.EDU>
Note: I haven't looked at today's draft yet. But here are some comments
on open issues, some of them based on talking with Danny Bobrow and some
of them based on questions from Dick Gabriel.
1. What is the story on the idea of built-in?
The key point here is that CLOS does not specify exactly which types are
built-in. We split "standard type class" into two things: the types
that are defined in Steele's book, which are candidates for being
built-in, and the built-in-class metaclass, which defines the ones that
actually are built-in in a given implementation. So we're allowing any
Common Lisp data type to be either built-in or a standard-class in a
particular implementation, but you can check the metaclass to see if it
is built-in. Also we're allowing implementations to make new
implementation-dependent built-in types, so the only thing that's
guaranteed -not- to be built-in are the standard classes you define
yourself. Also the structure classes I guess.
Danny points out that in the future we might want to make an incompatible
change to Common Lisp to require some particular type that is already in
Steele's book to be a standard-class rather than a built-in-class, whereas
in the initial version of CLOS this will be at the implementation's option.
For instance, one might want to do this to streams. Moon speaking again:
I don't see any CLtL types that are indubitably candidates for this, so
I think we can put off that issue.
It's implied by a paragraph on p.1-17, but it could be made clearer
in the commentary on Figure 1-1 that there can be additional,
implementation-dependent elements in the class precedence lists
of these types. CLOS only requires that the elements listed by
present and be in the order specified.
I'll try to send out in a separate message a cleanup of the built-in-class
message that Danny and Gregor sent, to be more appropriate to go into the
document. It's late, I guess that message won't go out until Tuesday.
2. UPDATE-INSTANCE-STRUCTURE and CLASS-CHANGED needed to be parallel
in how and who does initialization. Danny proposes that default primary methods
handle it in both cases. My view is that unless there is some meta-object
way to eliminate the initialization step, the only way is by putting
them into a primary method that can be shadowed or eliminated.
In talking to Danny last night, I came to believe that he thinks there
would be no meta-object way to get at the initialization in this step.
Actually, all of UPDATE-INSTANCE-STRUCTURE, CLASS-CHANGED, and
INITIALIZE-INSTANCE can usefully be consistent. This means that
for all three of these the default primary method is in charge of
initializing newly added slots that are not already initialized,
by evaluating the :initform and storing the result into the slot.
For UPDATE-INSTANCE-STRUCTURE and CLASS-CHANGED, values of slots
that already existed are transported into the updated instance
by something "at the bit level", before the generic function is
called. All three of these default primary methods are permitted
to conspire with the bit level to optimize out initforms that
neither produce nor depend on side-effects, by storing them into
the slots before the generic function is called rather than in the
default primary method. This optimization is still valid, but
not useful, when the default primary method has been shadowed.
Also implementations are permitted to open-code the body of the
default primary method in a way that makes it customized to a
specific class, rather than being forced to obtain information
from the class object and interpret it. However, this does not
change the user's ability to shadow the default primary method,
thus this optimization has to be done by open-coding rather than
by automatically generating a customized method on a more specific
class than STANDARD-OBJECT (I think this is grotesque, but it's the
only way to preserve the property that apparently people find highly
desirable of being able to turn off the evaluate-the-initforms
behavior without using a :AROUND method to turn everything off).
Changes from what we have now:
INITIALIZE-INSTANCE is not changed
UPDATE-INSTANCE-STRUCTURE -- the first bullet in the Remarks goes
away. Preserving the values of old slots is done at the bit level.
CLASS-CHANGED -- responsibility for evaluating the :initforms moves
from CHANGE-CLASS to CLASS-CHANGED (in the latest version of the
document I have, chapters 1 and 2 are inconsistent about this).
Responsibility for the rest of the structural transformation
remains with CHANGE-CLASS.
I think this shows that the use of standard method combination is wrong
for all three of these, because we have to keep telling people "don't
use :before methods, you'll be surprised, and don't use primary methods
unless you really mean to shadow the primary method." However, I know
I'm not going to change any minds on that point. If I was designing
this in a vacuum, I think I would make all three of these use PROGN
:MOST-SPECIFIC-LAST method combination, and then the user would not be
able to tell, except by using :AROUND methods, whether the initforms
are done by the default primary method or by the caller, and there
would be no way to write a method that does something unexpected,
so we wouldn't have to warn people about pitfalls.
3. What's the resolution on the CPL for NULL, SYMBOL, LIST et al?
The only one that's broken is the CPL for NULL. Either (null symbol list
sequence t) or (null list sequence symbol t) would be acceptable to me
and to Danny; the real problem is the (null list symbol sequence t) that
we have now. But we could say that was just a typo. Danny said he wanted
to check with Gregor in case G. had any strong opinion. I notice the
latest draft has (null symbol list sequence t) and I'm willing to live
with that.
4. What terminology for ``default primary method'' should we use?
We should define a class named STANDARD-OBJECT (this was the best name
Danny and I came up with), which is the least specific class, except for
T, in the CPL of any instance whose meta-class is STANDARD-CLASS. The
reason for existence of STANDARD-OBJECT is to allow there to be default
methods for instances of standard classes, that don't apply to instances
of other classes (built-in, structure, what have you). I hope with some
tweaking of the English the above paragraph can go into the document.
Most of the CPL examples will need to have STANDARD-OBJECT added to them.
There are several places in the spec which refer to the "default primary
method" when in fact they should be referring to the "primary method on
standard-object". The examples of this I can find right now are:
update-instance-structure (pg 1-13)
class-changed (pg 1-15)
initialize-instance (pg 1-34)
(For class-changed, we have to say which parameter is specialized.
I think the answer is, "both").
The point in these examples is that these "system supplied" methods are
actually providing default behavior for instances with metaclass
STANDARD-CLASS, so they should be on the class STANDARD-OBJECT, that's
what it's there for.
It's also likely that an implementation would want STANDARD-OBJECT
methods for PRINT-OBJECT and DESCRIBE, in addition to the T methods.
However, for these generic functions we say only that there is always
an applicable method, we don't say how the system-supplied methods
are modularized.
(Above text was Bidenized from Gregor in part.)
5. Are methods side-effected when method functions change?
One issue is, why should methods be different from classes and generic
functions? Both defclass and defgeneric side-effect an existing object,
they don't create a new object if there already is one with the name.
Another issue seems to be what happens if an error is signalled, e.g. due
to noncongruent lambda lists? Has the existing method object already
been side-effected when that happens? In general, CLtL never says what
the state of the program is at the time an error is signalled, and would
allow an implementation to choose whether to do the error-checking first
or the side-effects first. However, we might want CLOS to be a bit
cleaner. I don't see any reason not to do the error checking before the
side-effects.
We should see if Gregor comes up with some reason at the meta-object level
why it's really important that methods be inconsistent with generic functions
and classes. But in the absence of that, I think we ought to say that
defmethod side-effects an existing method object. We haven't said what
the macro expansion of defmethod is exactly, and perhaps that's meta-object
level business, but I think it might involve a function similar to
ensure-generic-function that takes enough keyword arguments to describe
the method, and either makes a new object or updates an existing one.
6. The reason that DEFMETHOD shouldn't specialize functions like CAR defaultly
is that the compiler has already compiled a pile of stuff knowing what's up.
WITH-ADDED-METHODS created lexical environment in which the compiler can know
all about that gives. Therefore, I think that if WITH-ADDED-METHODS is asked
to extend an ordinary function, it should make that function the method
function for the default primary method.
Another point is that this effect can be simulated with GENERIC-FLET, by
writing a default method that calls the old definition of the function
name. This suggest that there can't be much harm in allowing
WITH-ADDED-METHODS to do this. My only problem in evaluating this is that
I can't figure out what WITH-ADDED-METHODS is good for in the first place.
However I agree that WITH-ADDED-METHODS should be allowed to extend an
ordinary function.
7. What about the class named OBJECT? How does it fit in?
STANDARD-OBJECT, see above.
8. If CALL-NEXT-METHOD is globally bound to a function that signals
an error, the name CALL-NEXT-METHOD has indefinite scope. Is this
what we mean to say?
Well, the name has indefinite scope, but a particular binding of the name
to a useful value (not the global one that just signals an error) only has
lexical scope. I don't know the proper way to say this, but I think it is
what we mean to say.
By your comment about CALL-NEXT-METHOD's extent including the arguments
to the method, do you mean this:
(defmethod foo ((x1 c1) ... (xn Cn)
&optional (next-fun #'(lambda () (call-next-method))))...)
I guess this is ok.
Yes, that's what I mean. I guess the precise language would be that the
scope of the binding of CALL-NEXT-METHOD to a useful function includes
forms that appear in parameter specifiers of the defmethod, of course with
the exception of forms that appear in parameter specializer names of the
defmethod, since those latter forms are evaluated at definition time, not
at generic function call time.
Implementing this is epsilonically harder than allowing call-next-method
only in the body, but it seems to be what people will expect, and I'm
sure it's not enough harder to implement for implementation difficulty
to be a consideration.
By the way, this could also be written more simply
(defmethod foo ((x1 c1) ... (xn Cn)
&optional (next-fun #'call-next-method))...)
which is why we changed call-next-method from a macro to a function.
Another open issue is that initargs you have to pass to make-instance
when making a standard-method. I think the best bet is that in addition
to the initargs already documented, you must pass :lambda-list, which
is a lambda-list from which the implementation is permitted to derive
the number of required and optional arguments, the presence of rest/key
arguments, the keyword names, for lambda-list congruence computation.
An implementation is also permitted to ignore the :lambda-list argument
and get this information from the :function argument, if in that
implementation a lambda-list can be retrieved from a function (CLtL
doesn't require that). I think the lambda-list can be anything that
meets these requirements, so it can be the specialized-lambda-list that
appears in the defmethod form, or it can be an ordinary function lambda
list, or it can be the type of stripped down lambda-list that can
be used with defgeneric. I think it's better for the derivation of
lambda-list congruence information from lambda-lists to be in the system,
rather than being reimplemented by every user, hence I suggest a lot
of freedom in what kind of lambda-list the initarg can accept. The
alternative would be to require the user to pass two numbers, a boolean,
and a list of keyword names, but I'd rather not do it that way.
∂28-Oct-87 0856 Common-Lisp-Object-System-mailer Re: Proof of CLOS Document
Received: from SCORE.STANFORD.EDU by SAIL.STANFORD.EDU with TCP; 28 Oct 87 08:56:12 PST
Received: from hplabs.HP.COM (hplabs.hpl.hp.com.#Internet) by SCORE.STANFORD.EDU with TCP; Wed 28 Oct 87 08:52:37-PST
Received: from hplms2 by hplabs.HP.COM with SMTP ; Wed, 28 Oct 87 08:55:27 PST
Received: from hplabsz.hpl.hp.com by hplms2; Wed, 28 Oct 87 08:54:59 pst
Return-Path: <kempf@hplabsz>
Received: from hplabsz by hplabsz; Wed, 28 Oct 87 09:54:27 pst
To: "David A. Moon" <Moon@STONY-BROOK.SCRC.Symbolics.COM>
Cc: kempf%hplabsz@hplabs.HP.COM, common-lisp-object-system@SAIL.STANFORD.EDU
Subject: Re: Proof of CLOS Document
X-Mailer: mh6.5
In-Reply-To: Your message of Tue, 27 Oct 87 11:45:00 -0500.
<19871027164545.7.MOON@EUPHRATES.SCRC.Symbolics.COM>
Date: Wed, 28 Oct 87 08:54:23 PST
Message-Id: <388.562438463@hplabsz>
From: kempf%hplabsz@hplabs.HP.COM
New page numbers refer to the draft on SAIL as of Oct. 22, which
may be out of date with the current draft, since I've not had
a chance to update.
> pg. 1-17: Last Paragraph. It is not clear from this what should happen
> if (TYPE-OF <obj>) returns a type speciifer which is a list. Should an
> error be signalled or should the CAR of the list be used? On pg. 42 of
> CLtL, the description of type specifiers which are lists suggests
> that the CAR should work.
> Is this the page that has figure 1-1 on it? I can't find anything on that
> page that looks like what you're referring to. I suspect you've uncovered
> a problem here, but I can't find the problem. Note however that the
> second paragraph on page 1-16, where it says (type-of I) is S if S is
> the proper name of C, else C, should say that this only applies when C
> is an instance of STANDARD-CLASS.
Yes, this is the page with Fig. 1-1. I think what I'm trying to anticipate
is implementation problems. Re-reading the second paragraph on page 1-16,
the specification seems to be clear on this. If TYPE-OF returns a list,
then it's up to the implementation to make sure the first element is
used in SYMBOL-CLASS.
> Overall: When referring to SETF functions, the list specifying a
> SETF function name is often not quoted. Example: (fboundp (setf <name>)).
> If the argument had been a function symbol name, however, it would have
> been quoted, since FBOUNDP is a function and therefore the arguments
> are evaluated. Shouldn't this be so for SETF function names as well,
> or is the assumption that (SETF <name>) is a macro which returns the
> actual name of the function (e.g. expands into something like '<actual na
me>)?
> It's just missing quote marks; no hairy macro like that was intended.
> Do you have page references for these typos? I think I noticed one or two,
> but they're easy to overlook and you probably saw some that I missed.
I marked some of them down. Here they are:
pg. 2-24, 4th paragraph; pg. 2-36, 4th paragraph; pg. 2-40 2nd bullet item;
pg 2-42, 1st paragraph under ARGUMENTS
> pg. 2-30: Top of page. I'm curious if the form generated is expected to
> be executable. That is, if <operator> can be a keyword symbol, then the
> implicit assumption is that the function cell of keywords can be
> bound. I know this is possible in Symbolics CL and not in ours, also
> I don't think CLtL says anything either way. Is there a Cleanup proposal
> on this?
> This moved to 2-29 in the latest draft (if things are getting shorter, that's
> a good sign!). I don't see anything that implies here that an implementation
> has to allow <operator> to be a keyword symbol. Certainly that was not
> intended. On the other hand, I don't know of anything in CLtL that allows
> implementations to forbid defining keyword symbols as functions. Anyway,
> the intent here is that <operator> is the name of a function, macro, or
> special form and can appear in the car of a form; precisely what objects
> satisfy that criterion is defined by CL rather than CLOS.
As mentioned, CLtL says nothing either way about whether keyword symbols
can be defined as functions. The only reason I asked about this was because
the last sentence in that paragraph states that <operator> can be specified
by a keyword option. If there are any other implementations besides ours
which have chosen to forbid binding the function cell of a keyword symbol
to a function, this might be a problem.